实现层级账号及其各层级广告数据更新

This commit is contained in:
hgc 2024-12-31 20:10:19 +08:00
parent 01247881b2
commit 14301a08e4
23 changed files with 1151 additions and 731 deletions

View File

@ -0,0 +1,113 @@
<?php
namespace app\controller;
use app\service\GoogleOAuthService;
use app\service\GoogleAdsAccountService;
use Google\ApiCore\ApiException;
use support\Request;
use support\Response;
use DI\Annotation\Inject;
//use app\model\ThirdUserAdvertiser;
class CustomerController
{
/**
* @Inject
* @var GoogleOAuthService
*/
private $googleOAuthService;
/**
* @Inject
* @var GoogleAdsAccountService
*/
private $googleAdsAccountService;
//绑定某个广告账号
public function bindAdvertiser(Request $request)
{
$customerId = $request->input('customer_id'); // 需要绑定的广告账号 ID
$thirdUserId = $request->input('third_user_id'); // bps_third_user的id
$googleOAuthService = new GoogleOAuthService();
$hasThirdUser = $googleOAuthService->bindThirdUserAdvertiser($customerId, $thirdUserId);
if (!$hasThirdUser) {
return $this->errorResponse(300, 'Invalid state parameter');
}
return $this->successResponse($hasThirdUser);
}
public function getCustomerList(Request $request)
{
$thirdUserId = $request->input('third_user_id'); // bps_third_user的id
$googleOAuthService = new GoogleOAuthService();
$hasThirdUser = $googleOAuthService->getCustomerList($thirdUserId);
if (!$hasThirdUser) {
return $this->errorResponse(300, 'Invalid state parameter');
}
return $this->successResponse($hasThirdUser);
}
public function accessibleCustomers(Request $request)
{
$options = $request->all();
// 继续处理 Google Ads API 操作
return $this->listAccessibleCustomers($options);
}
public function accountHierarchy(Request $request)
{
$options = $request->all();
// 继续处理 Google Ads API 操作
return $this->getAccountHierarchy($options);
}
/**
* 关联广告客户ID
* @throws ApiException
*/
public function listAccessibleCustomers($options): Response
{
$resourceName = $this->googleAdsAccountService->runListAccessibleCustomers($options);
return $this->successResponse(['links_resource_name' => $resourceName]);
}
/**
* 广告主体下层级账号
* @throws ApiException
*/
public function getAccountHierarchy($options): Response
{
$resourceName = $this->googleAdsAccountService->runGetAccountHierarchy($options);
return $this->successResponse(['links_resource_name' => $resourceName]);
}
// 可以加入一些公共方法
protected function successResponse($data): Response
{
return Json([
'code' => 0,
'msg' => 'ok',
'data' => $data,
]);
}
protected function errorResponse($code, $message, $data = []): Response
{
return Json([
'code' => $code,
'msg' => $message ?: 'error',
'data' => $data
]);
}
}

View File

@ -2,8 +2,6 @@
namespace app\controller; namespace app\controller;
use app\model\Campaign as CampaignModel;
use app\model\CampaignBudget;
use Google\ApiCore\ApiException; use Google\ApiCore\ApiException;
use support\Request; use support\Request;
use app\service\GoogleAdsCampaignService; use app\service\GoogleAdsCampaignService;
@ -12,6 +10,7 @@ use app\service\GoogleAdsAdService;
use app\service\GoogleAdsAssetService; use app\service\GoogleAdsAssetService;
use app\service\GoogleAdsAssetRelationService; use app\service\GoogleAdsAssetRelationService;
use app\service\GoogleAdsAccountService; use app\service\GoogleAdsAccountService;
//use app\service\GoogleOAuthService;
use support\Response; use support\Response;
use DI\Annotation\Inject; use DI\Annotation\Inject;
use think\facade\Db as ThinkDb; use think\facade\Db as ThinkDb;
@ -79,7 +78,7 @@ class GoogleAdsController
public function listGroups(Request $request) public function listGroups(Request $request)
{ {
$options = $request->all(); $options = $request->all();
// 继续处理 Google Ads API 操作 // 继续处理 Google Ads API 操作
return $this->getGroups($options); return $this->getGroups($options);
@ -207,12 +206,6 @@ class GoogleAdsController
return $this->addLinkManagerToClient($options); return $this->addLinkManagerToClient($options);
} }
public function accessibleCustomers(Request $request)
{
// $options = $request->all();
// 继续处理 Google Ads API 操作
return $this->listAccessibleCustomers();
}
/** /**
* 创建广告系列 * 创建广告系列
@ -248,15 +241,6 @@ class GoogleAdsController
return $this->successResponse(['link_resource_name' => $resourceName]); return $this->successResponse(['link_resource_name' => $resourceName]);
} }
/**
* 关联广告客户ID
* @throws ApiException
*/
public function listAccessibleCustomers(): Response
{
$resourceName = $this->googleAdsAccountService->runListAccessibleCustomers();
return $this->successResponse(['links_resource_name' => $resourceName]);
}
/** /**
* get campaigns * get campaigns
@ -274,7 +258,7 @@ class GoogleAdsController
*/ */
public function getGroups($options): Response public function getGroups($options): Response
{ {
$resourceName = $this->googleAdsGroupService->runListGroups($options['customer_id']); $resourceName = $this->googleAdsGroupService->runListGroups($options['customer_id'], $options);
return $this->successResponse(['groups_list' => $resourceName]); return $this->successResponse(['groups_list' => $resourceName]);
} }
/** /**
@ -283,7 +267,7 @@ class GoogleAdsController
*/ */
public function getAds($options): Response public function getAds($options): Response
{ {
$resourceName = $this->googleAdsAdService->runListAds($options['customer_id']); $resourceName = $this->googleAdsAdService->runListAds($options['customer_id'],$options);
return $this->successResponse(['groups_list' => $resourceName]); return $this->successResponse(['groups_list' => $resourceName]);
} }

View File

@ -7,11 +7,9 @@ use support\Request;
use support\Response; use support\Response;
use DI\Annotation\Inject; use DI\Annotation\Inject;
use app\model\ThirdUserAdvertiser; use app\model\ThirdUserAdvertiser;
use app\event\GoogleAdsCampaigns; use app\model\ThirdUser;
use app\event\GoogleAdsGroups;
use app\event\GoogleAdsAds; use app\event\GoogleAdsCustomers;
use app\event\GoogleAdsDateDatas;
use app\event\GoogleAdsMaterials;
use Webman\Event\Event; use Webman\Event\Event;
class OAuthController class OAuthController
@ -24,9 +22,10 @@ class OAuthController
private $googleOAuthService; private $googleOAuthService;
public function getAuthCode() public function getAuthCode(Request $request)
{ {
$authUrl = $this->googleOAuthService->getAuthUrl(); $state = $request->get('state') ?? $request->jwtClaims['uid'];
$authUrl = $this->googleOAuthService->getAuthUrl($state);
return $this->successResponse([ return $this->successResponse([
'url' => $authUrl, 'url' => $authUrl,
]); ]);
@ -35,30 +34,36 @@ class OAuthController
public function handleCallback(Request $request) public function handleCallback(Request $request)
{ {
// $state = $request->input('state'); // 从Google回调中获取state $state = $request->input('state'); // 从Google回调中获取state
$code = $request->input('code'); // 授权码 $code = $request->input('code'); // 授权码
// 验证state值是否与保存的值一致 if (!$state) {
// if ($state !== $_SESSION['oauth_state']) { return $this->errorResponse(300, 'Invalid state parameter');
// if ($state !== '7a7a9edad5b48c127b7c14fabe39fae0') { }
// return $this->errorResponse(400, 'Invalid state parameter');
// }
// state值验证通过继续处理授权码 // state值验证通过继续处理授权码
$googleOAuthService = new GoogleOAuthService(); $googleOAuthService = new GoogleOAuthService();
$tokens = $googleOAuthService->getRefreshToken($code);
$tokens = $googleOAuthService->getRefreshToken($code);
if (!isset($tokens['refresh_token'])) { if (!isset($tokens['refresh_token'])) {
return $this->errorResponse(300, 'Invalid state parameter'); return $this->errorResponse(300, 'Invalid state parameter');
}else{ } else {
// 保存refresh token到数据库 $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $state);
$googleOAuthService->updateRefreshToken($tokens['refresh_token'], $tokens['access_token']);
// 根据新用户绑定插入新数据todo
// if(!$result) {
// $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $tokens['access_token']);
// }
} }
// if (getenv('GOOGLE_DEVELOP_TOKEN_LEVEL') === 'test') {
// $option['manager_customer_id'] = '1401879025'; //开发者
// $option['login_customer_id'] = '1401879025';
// }
// $option['refresh_token'] = $tokens['refresh_token'];
//
// $thirdUser = ThirdUser::where('access_token', $tokens['refresh_token'])->find(); // 获取第一个结果
// if ($thirdUser) {
// $option['third_user_id'] = $thirdUser->id;
// Event::emit(GoogleAdsCustomers::CUSTOMERADD, $option);
// } else {
// return $this->errorResponse(300, 'Invalid state parameter');
// }
return $this->successResponse($tokens); return $this->successResponse($tokens);
} }
public function getRefreshToken(Request $request) public function getRefreshToken(Request $request)
@ -93,34 +98,55 @@ class OAuthController
public function revokeRefreshToken(Request $request) public function revokeRefreshToken(Request $request)
{ {
// $accessToken = $request->input('token'); //access token // $accessToken = $request->input('token'); //access token
// $customerId = isset($requestData['ad_customer_id']) ? $requestData['ad_customer_id'] : getenv('GOOGLE_ADS_CUSTOMER_ID'); // $customerId = isset($requestData['customer_id']) ? $requestData['customer_id'] : getenv('GOOGLE_ADS_CUSTOMER_ID');
$customerId = getenv('GOOGLE_ADS_CUSTOMER_ID'); //临时指定 // $customerId = getenv('GOOGLE_ADS_CUSTOMER_ID'); //临时指定
$uid = $request->input('user_id');
// 通过 advertiser_id 查询 ThirdUserAdvertiser联表查询 ThirdUser 数据 // 通过 advertiser_id 查询 ThirdUserAdvertiser联表查询 ThirdUser 数据
$userAdvertiser = ThirdUserAdvertiser::with('googleUser') // 联表查询 user 关联 $thirdUser = ThirdUser::where('user_id', $uid)->find(); // 获取第一个结果
->where('advertiser_id', $customerId) // 根据 advertiser_id 查询 // dump($thirdUser); return ($uid);
->find(); // 获取第一个结果 if (!$thirdUser) {
return $this->errorResponse(300, '未授权');
}
// dump($userAdvertiser->googleUser->access_token); // dump($userAdvertiser->googleUser->access_token);
$accessToken = $userAdvertiser->googleUser->access_token; $accessToken = $thirdUser->access_token;
$googleOAuthService = new GoogleOAuthService(); $googleOAuthService = new GoogleOAuthService();
$googleOAuthService->revokeToken($accessToken); $googleOAuthService->revokeToken($accessToken, $thirdUser->id);
return $this->successResponse(['deleted' => 'success']); return $this->successResponse(['deleted' => 'success']);
} }
//保存某个主体的全部access广告账号
function saveAdvertisers(Request $request)
{
$customerIds = $request->input('third_user_list_customers'); // customer_id_list每个元素包含advertiser_id
// $thirdUserId = $request->input('third_user_id'); // bps_third_user的id
$googleOAuthService = new GoogleOAuthService();
$hasThirdUser = $googleOAuthService->bindThirdUserAdvertiser($customerId, $thirdUserId);
if (!$hasThirdUser) {
return $this->errorResponse(300, 'Invalid state parameter');
}
return $this->successResponse($hasThirdUser);
}
public function testRefreshToken(Request $request) public function testRefreshToken(Request $request)
{ {
// 接建立socket连到内部推送端口 // 接建立socket连到内部推送端口
$client = stream_socket_client('tcp://192.168.21.27:22101', $errorCode, $errorMessage); $client = stream_socket_client('tcp://192.168.21.27:22101', $errorCode, $errorMessage);
if (false === $client) { if (false === $client) {
throw new \Exception('rpc failed to connect: '.$errorMessage); throw new \Exception('rpc failed to connect: ' . $errorMessage);
} }
$rpc_request = [ $rpc_request = [
'class' => 'Auth', 'class' => 'Auth',
'method' => 'ValidateJwtToken', 'method' => 'ValidateJwtToken',
'args' => [ 'args' => [
[ [
'uid' => 2023, 'uid' => 2023,
'username' => 'Tinywan', 'username' => 'Tinywan',
@ -128,7 +154,7 @@ class OAuthController
] ]
]; ];
// 发送数据注意5678端口是Text协议的端口Text协议需要在数据末尾加上换行符 // 发送数据注意5678端口是Text协议的端口Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($rpc_request)."\n"); fwrite($client, json_encode($rpc_request) . "\n");
// 读取推送结果 // 读取推送结果
$result = fgets($client, 10240000); $result = fgets($client, 10240000);
// 解析JSON字符串 // 解析JSON字符串

View File

@ -55,9 +55,9 @@ class GoogleAdsAds
public function getAds($options) public function getAds($options)
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { foreach ($customers as $customer) {
$googleAdsAdService = new GoogleAdsAdService($customerId); $googleAdsAdService = new GoogleAdsAdService($customer['customer_id']);
$resourceName = $googleAdsAdService->runListAds($customerId); $resourceName = $googleAdsAdService->runListAds($customer['customer_id'],$customer);
} }
// return $this->successResponse(['ads_list' => $resourceName]); // return $this->successResponse(['ads_list' => $resourceName]);

View File

@ -56,9 +56,10 @@ class GoogleAdsAssetRelations
public function getAssetRelations($options) public function getAssetRelations($options)
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { foreach ($customers as $customer) {
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId); // dump($customer);
$resourceName = $googleAdsAssetRelationService->runListAssetRelations($customerId); $googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customer['customer_id']);
$resourceName = $googleAdsAssetRelationService->runListAssetRelations($customer['customer_id']);
} }
// return $this->successResponse(['ads_list' => $resourceName]); // return $this->successResponse(['ads_list' => $resourceName]);
@ -70,9 +71,9 @@ class GoogleAdsAssetRelations
public function getVideoAssetRelations($options) public function getVideoAssetRelations($options)
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { foreach ($customers as $customer) {
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId); $googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customer['customer_id']);
$resourceName = $googleAdsAssetRelationService->runListVideoAssetRelations($customerId); $resourceName = $googleAdsAssetRelationService->runListVideoAssetRelations($customer['customer_id']);
} }
// return $this->successResponse(['ads_list' => $resourceName]); // return $this->successResponse(['ads_list' => $resourceName]);

View File

@ -55,9 +55,9 @@ class GoogleAdsAssets
public function getAssets($options) public function getAssets($options)
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { foreach ($customers as $customer) {
$googleAdsAssetService = new GoogleAdsAssetService($customerId); $googleAdsAssetService = new GoogleAdsAssetService($customer['customer_id']);
$resourceName = $googleAdsAssetService->runListAssets($customerId); $resourceName = $googleAdsAssetService->runListAssets($customer['customer_id'],$customer);
} }
// return $this->successResponse(['ads_list' => $resourceName]); // return $this->successResponse(['ads_list' => $resourceName]);

View File

@ -59,9 +59,10 @@ class GoogleAdsCampaigns
public function getCampaigns($options) public function getCampaigns($options)
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { // dump($customers);
$googleAdsCampaignService = new googleAdsCampaignService($customerId); foreach ($customers as $customer) {
$resourceName = $googleAdsCampaignService->runListCampaigns($customerId); $googleAdsCampaignService = new googleAdsCampaignService($customer['customer_id']);
$resourceName = $googleAdsCampaignService->runListCampaigns($customer['customer_id'],$customer);
} }
// return $this->successResponse(['campaigns_list' => $resourceName]); // return $this->successResponse(['campaigns_list' => $resourceName]);
} }

View File

@ -0,0 +1,325 @@
<?php
namespace app\event;
use app\model\ThirdUser;
use app\service\GoogleAdsAssetService;
use app\service\GoogleOAuthService;
use app\service\GoogleAdsAccountService;
use Google\ApiCore\ApiException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use support\Db;
use support\Request;
use support\Response;
use DI\Annotation\Inject;
//use QL\QueryList;
use support\Redis;
class GoogleAdsCustomers
{
/**
* @Inject
* @var GoogleOAuthService
*/
private $googleOAuthService;
/**
* @Inject
* @var GoogleAdsAccountService
*/
private $googleAdsAccountService;
//微博热榜地址
// const url = 'https://library.tiktok.com/api/v1/search?region=GB&type=1&start_time=1666540800&end_time=1666627200';
const userAgent = 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
const type = 'googleadscustomers';
const CUSTOMERADD = 'googleadsaddcustomers';
const limit = 12;
const sort_order = 'impression,desc';
// const countries = ["AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE","IT", "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "CH", "TR", "GB"] ;
const countries = ["GB", "BE"];
public function addCustomers()
{
// dump($options);
$thirdUser = ThirdUser::where('is_default', 'f')->where('third_type', 'google')
->find();
if (getenv('GOOGLE_DEVELOP_TOKEN_LEVEL') === 'test') {
$option['manager_customer_id'] = '1401879025'; //开发者
$option['login_customer_id'] = '1401879025';
}
$option['refresh_token'] = $thirdUser->access_token;
// dump($option);
$allRootAccounts = $this->googleAdsAccountService->runGetAccountHierarchy($option);
// dump($allAccounts);
foreach ($allRootAccounts as $rootAccountId => $accounts) {
// dump($rootAccountId, $accounts);
foreach ($accounts as $account) {
$customerId = $account['customer_id'];
$customerName = $account['descriptive_name'];
// dump($customerId, $customerName, $thirdUser->id);
$this->googleOAuthService->saveThirdUserAdvertiser($customerId, $thirdUser->id,$rootAccountId, $customerName);
}
}
// return $this->successResponse($allAccounts);
}
public function listCustomers(Request $request)
{
$options = $request->all();
// 继续处理 Google Ads API 操作
return $this->getCustomers($options);
}
/**
* get assets
* @throws ApiException
*/
public function getAccountHierarchy($options)
{
$resourceName = $this->googleAdsAccountService->runGetAccountHierarchy($options);
return $this->successResponse(['links_resource_name' => $resourceName]);
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) {
$googleAdsAssetService = new GoogleAdsAssetService($customerId);
$resourceName = $googleAdsAssetService->runListAssets($customerId);
}
// return $this->successResponse(['ads_list' => $resourceName]);
}
/**
* 每天爬取tiktok广告
* @return void
*/
public function update()
{
try {
$client = new Client([
//允许重定向
// 'allow_redirects' => true,
]);
// 获取前两天 0 点的时间戳
$dayBeforeYesterdayStart = strtotime('-2 days 00:00:00');
// 获取前一天 0 点的时间戳
$yesterdayStart = strtotime('-1 day 00:00:00');
$countryCache = Redis::get(self::type . 'lastCountry');
//全部跑完跳出
if ($countryCache == 'All') {
dump($countryCache . '国家更新tiktok Ads 完成');
return;
}
if (empty($countryCache)) {
$countryCache = 'GB';
}
$searchIdCache = Redis::get(self::type . 'lastSearchId');
$offsetCache = Redis::get(self::type . 'nextOffset');
$totalCache = Redis::get(self::type . 'totalCache');
if (!isset($searchIdCache) || empty($searchIdCache)) {
$searchIdCache = '';
}
if (!isset($offsetCache) || empty($searchIdCache)) {
$offsetCache = 0;
}
if (!isset($totalCache) || empty($searchIdCache)) {
$totalCache = 0;
}
//判断国家是否跑完。
if ($totalCache > 0 && $offsetCache > ceil($totalCache / self::limit)) {
$key = array_search($countryCache, self::countries, true);
if (in_array($countryCache, self::countries) && isset(self::countries[$key + 1])) {
$countryCache = self::countries[$key + 1];
dump('更新' . $countryCache . '国家的tiktok Ads 完成');
} else {
$countryCache = 'All'; //赋值非正常国家的code中断定时任务
dump($countryCache . '国家更新tiktok Ads 完成');
}
return;
}
$start_time = $dayBeforeYesterdayStart;
$end_time = $yesterdayStart;
//当前国家爬取
$currentParams = null;
$currentParams = ['country' => $countryCache, 'search_id' => $searchIdCache, 'type' => 1, 'start_time' => $start_time, 'end_time' => $end_time];
$url = 'https://library.tiktok.com/api/v1/search?region=' . $currentParams['country'] . '&type=' . $currentParams['type'] . '&start_time=' . $currentParams['start_time'] . '&end_time=' . $currentParams['end_time'];
$res = json_decode($client->post($url, [
'headers' => [
'accept' => 'application/json, text/plain, */*',
'accept-language' => 'zh-CN,zh;q=0.9',
'content-type' => 'application/json',
'cookie' => 'cookie: _ttp=2ov8Fc4C2CaNscHJd90O9fMhlpE; _ga=GA1.1.1025820618.1731926196; FPID=FPID2.2.Bcgkp%2Fk%2Bbn5w5YeSMR9wd9VpNHJwTUpkkaEqSdCEa0w%3D.1731926196; FPAU=1.2.944915349.1731926193; FPLC=mbVyryI5aG6IVpAvhs1JsgWjA7FVA6QsCJ7VbXhM7zWoXNp4rcD0IK7FNTTf%2FuOrqeOgqEhTd4NB3hY7q3aDVTGQa3WGHqxkGte4%2BBZxsrpaHFas9kb7DPRXM12T5Q%3D%3D; _ga_TEQXTT9FE4=GS1.1.1732097542.7.0.1732097542.0.0.857840528',
'origin' => 'https://library.tiktok.com',
'priority' => 'u=1, i',
'referer' => 'https://library.tiktok.com/ads?region=AT&start_time=1731945600000&end_time=1732032000000&adv_name=&adv_biz_ids=&query_type=&sort_type=last_shown_date,desc',
'sec-ch-ua' => '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
'sec-ch-ua-mobile' => '?0',
'sec-ch-ua-platform' => '"Windows"',
'sec-fetch-dest' => 'empty',
'sec-fetch-mode' => 'cors',
'sec-fetch-site' => 'same-origin',
'user-agent' => self::userAgent,
// 'user-agent' => 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
],
'json' => [
'query' => '',
'query_type' => '',
'adv_biz_ids' => '',
'order' => self::sort_order,
'offset' => (int)$offsetCache,
'search_id' => $currentParams['search_id'],
'limit' => self::limit,
],
])->getBody()->getContents(), true);
// dump($res);return; //调试点
if ($res['search_id'] != $searchIdCache) {
$searchIdCache = $res['search_id'];
dump('search_id更新 ' . $searchIdCache . ' 成功');
}
if ($res['total'] == 0 || $res['code'] != 0) {
dump('更新tiktok Ads接口响应异常' . json_encode($res, JSON_UNESCAPED_UNICODE));
return;
}
$listAdsIds = [];
foreach ($res['data'] as $ad) {
if ($ad['audit_status'] == 2 || empty($ad['videos'])) {
continue; //审核不过或者没视频不采集
}
$imagesJson = is_array($ad['image_urls']) ? json_encode($ad['image_urls']) : json_encode([]);
$rejection_info = is_array($ad['rejection_info']) ? json_encode($ad['rejection_info']) : null;
// dump($rejection_info);
$insertData[$ad['id']] = [
'ad_id' => $ad['id'],
'name' => $ad['name'],
'audit_status' => $ad['audit_status'],
'type' => $ad['type'],
'first_shown_date' => $ad['first_shown_date'],
'last_shown_date' => $ad['last_shown_date'],
'image_urls' => $imagesJson,
'estimated_audience' => $ad['estimated_audience'],
'spent' => $ad['spent'],
'impression' => $ad['impression'],
'show_mode' => $ad['show_mode'],
'rejection_info' => $rejection_info,
'sor_audit_status' => $ad['sor_audit_status'],
'country_code' => $countryCache,
];
if (isset($ad['videos']) && !empty($ad['videos'])) {
// 遍历 "videos" 数组
foreach ($ad['videos'] as $video) {
$insertData[$ad['id']]['video_url'] = $video['video_url'];
$insertData[$ad['id']]['cover_img'] = $video['cover_img'];
}
}
$listAdsIds = array_column($insertData, 'ad_id');
}
// dump($insertData);return;
if (empty($insertData)) return;
//开启事务
Db::beginTransaction();
//删除原来的旧数据
TiktokAd::query()->whereIn('ad_id', array_keys($insertData))->delete();
//添加新的数据
TiktokAd::query()->insert($insertData);
//redis缓存
Redis::set(self::type, json_encode($insertData, JSON_UNESCAPED_UNICODE));
//redis缓存 记录更新时间
$time = date('Y-m-d H:i:s');
Redis::set(self::type . 'time', $time);
Redis::set(self::type . 'lastCountry', $countryCache);
Redis::set(self::type . 'nextOffset', ++$offsetCache); //记录下一次的offset
Redis::set(self::type . 'totalCache', $res['total']);
Redis::set(self::type . 'lastSearchId', $searchIdCache);
if (!empty($listAdsIds)) {
Redis::rPush(self::type . 'AdsIds', ...$listAdsIds);
}
//提交事务
Db::commit();
//销毁$res
unset($res);
dump(date('Y-m-d H:i:s') . '更新' . self::type . '成功');
} catch (GuzzleException|\Exception $exception) {
//回滚事务
Db::rollBack();
dump('更' . self::type . '异常:' . $exception->getMessage());
dump($exception);
}
// } catch (ClientExceptionInterface $e) {
// // 捕获 4xx 错误
// dump( 'Client error: ' . $e->getMessage() . "\n");
// } catch (ServerExceptionInterface $e) {
// // 捕获 5xx 错误
// dump('Server error: ' . $e->getMessage() . "\n");
// } catch (TransportExceptionInterface $e) {
// // 捕获网络传输错误
// dump('Transport error: ' . $e->getMessage() . "\n") ;
// } catch (\Exception $e) {
// // 捕获所有其他错误
// dump('General error: ' . $e->getMessage() . "\n") ;
// }
}
// 可以加入一些公共方法
protected function successResponse($data): Response
{
return Json([
'code' => 0,
'msg' => 'ok',
'data' => $data,
]);
}
protected function errorResponse($code, $message, $data = []): Response
{
return Json([
'code' => $code,
'msg' => $message ?: 'error',
'data' => $data
]);
}
}

View File

@ -58,10 +58,9 @@ class GoogleAdsGroups
{ {
$customers = $this->googleOAuthService->getGoogleAdCustomers([]); $customers = $this->googleOAuthService->getGoogleAdCustomers([]);
foreach ($customers as $customerId) { foreach ($customers as $customer) {
$googleAdsGroupService = new GoogleAdsGroupService($customerId); $googleAdsGroupService = new GoogleAdsGroupService($customer['customer_id']);
$resourceName = $googleAdsGroupService->runListGroups($customer['customer_id'],$customer);
$resourceName = $googleAdsGroupService->runListGroups($customerId);
// return $this->successResponse(['groups_list' => $resourceName]); // return $this->successResponse(['groups_list' => $resourceName]);
} }

View File

@ -2,6 +2,7 @@
namespace app\model; namespace app\model;
use think\Model; use think\Model;
use app\model\ThirdUserAdvertiser;
class ThirdUser extends Model class ThirdUser extends Model
{ {
@ -25,4 +26,11 @@ class ThirdUser extends Model
{ {
return $this->hasMany(ThirdUserAdvertiser::class, 'doc_', 'id'); return $this->hasMany(ThirdUserAdvertiser::class, 'doc_', 'id');
} }
// 使用 onBeforeDelete 事件来级联删除广告主记录
// public static function onBeforeDelete($thirdUser)
// {
// // 在删除 ThirdUser 时,删除所有与之关联的 ThirdUserAdvertiser 记录
// $thirdUser->advertisers()->delete();
// }
} }

View File

@ -4,6 +4,7 @@ namespace app\process;
use app\event\GoogleAdsCampaigns; use app\event\GoogleAdsCampaigns;
use app\event\GoogleAdsCustomers;
use app\event\GoogleAdsGroups; use app\event\GoogleAdsGroups;
use app\event\GoogleAdsAds; use app\event\GoogleAdsAds;
use app\event\GoogleAdsAssets; use app\event\GoogleAdsAssets;
@ -49,36 +50,36 @@ class UpdateGoogleAdsTask
} }
); );
// 每15分钟执行一次 // 每15分钟执行一次
new Crontab('40 */15 * * * *', function () { new Crontab('15 */10 * * * *', function () {
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始'); dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始');
// Event::emit(GoogleAdsCampaigns::type, []); Event::emit(GoogleAdsCampaigns::type, []);
} }
); );
// 每15分钟执行一次 // 每15分钟执行一次
new Crontab('50 */15 * * * *', function () { new Crontab('30 */10 * * * *', function () {
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsGroups::type . '开始'); dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsGroups::type . '开始');
Event::emit(GoogleAdsGroups::type, []); Event::emit(GoogleAdsGroups::type, []);
} }
); );
// 每15分钟执行一次 // 每15分钟执行一次
new Crontab('55 */15 * * * *', function () { new Crontab('5 */11 * * * *', function () {
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始'); dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始');
// Event::emit(GoogleAdsAds::type, []); Event::emit(GoogleAdsAds::type, []);
} }
); );
// 每15分钟执行一次 // 每15分钟执行一次
new Crontab('25 */15 * * * *', function () { new Crontab('25 */19 * * * *', function () {
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始'); dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始');
// Event::emit(GoogleAdsAssets::type, []); Event::emit(GoogleAdsAssets::type, []);
} }
); );
new Crontab('55 */50 * * * *', function () { new Crontab('*/20 * * * * *', function () {
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始'); dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始');
// Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []); Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []);
}); });
new Crontab('55 */51 * * * *', function () { new Crontab('55 */51 * * * *', function () {
@ -87,6 +88,12 @@ class UpdateGoogleAdsTask
} }
); );
new Crontab('0 */15 * * * *', function () {
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCustomers::CUSTOMERADD . '开始');
Event::emit(GoogleAdsCustomers::CUSTOMERADD,[]);
}
);
// 每15分钟执行一次 // 每15分钟执行一次

View File

@ -2,7 +2,7 @@
// app/service/BaseService.php // app/service/BaseService.php
namespace app\service; namespace app\service;
use app\model\ThirdUserAdvertiser; use app\model\ThirdUser;
use think\db\exception\BindParamException; use think\db\exception\BindParamException;
use think\facade\Db as ThinkDb; use think\facade\Db as ThinkDb;
use app\model\Campaign as CampaignModel; use app\model\Campaign as CampaignModel;
@ -84,19 +84,18 @@ class BaseService
/** /**
* 从数据库获取 refreshToken * 从数据库获取 refreshToken
* *
* @param string $advertiserId 广告主ID * @param string $thirdUserId 广告主ID
* @return string|null * @return string|null
*/ */
public function getRefreshTokenFromDatabase($advertiserId) public function getRefreshTokenFromDatabase($thirdUserId)
{ {
// 通过 advertiser_id 查询 ThirdUserAdvertiser联表查询 ThirdUser 数据 // 通过 advertiser_id 查询 ThirdUserAdvertiser联表查询 ThirdUser 数据
$userAdvertiser = ThirdUserAdvertiser::with('googleUser') $thirdUser = ThirdUser::find($thirdUserId);
->where('advertiser_id', $advertiserId) //dump($thirdUser);
->find();
// 如果找到广告主数据 // 如果找到广告主数据
if ($userAdvertiser && $userAdvertiser->googleUser) { if ($thirdUser) {
return $userAdvertiser->googleUser->access_token; // 返回 access_token return $thirdUser->access_token; // 返回 access_token
} }
return null; // 如果没有找到,返回 null return null; // 如果没有找到,返回 null

View File

@ -9,26 +9,36 @@ use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient; use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder; use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException; use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsServerStreamDecorator;
use Google\Ads\GoogleAds\Util\FieldMasks; use Google\Ads\GoogleAds\Util\FieldMasks;
use Google\Ads\GoogleAds\Util\V18\ResourceNames; use Google\Ads\GoogleAds\Util\V18\ResourceNames;
use Google\Ads\GoogleAds\V18\Enums\ManagerLinkStatusEnum\ManagerLinkStatus; use Google\Ads\GoogleAds\V18\Enums\ManagerLinkStatusEnum\ManagerLinkStatus;
use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError; use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V18\Resources\CustomerClient;
use Google\Ads\GoogleAds\V18\Services\Client\CustomerServiceClient;
//use Google\Ads\GoogleAds\V18\Services\CustomerServiceClient;
use Google\Ads\GoogleAds\V18\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V18\Services\ListAccessibleCustomersRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsStreamRequest;
use Google\Ads\GoogleAds\V18\Resources\CustomerClientLink; use Google\Ads\GoogleAds\V18\Resources\CustomerClientLink;
use Google\Ads\GoogleAds\V18\Resources\CustomerManagerLink; use Google\Ads\GoogleAds\V18\Resources\CustomerManagerLink;
use Google\Ads\GoogleAds\V18\Services\CustomerClientLinkOperation; use Google\Ads\GoogleAds\V18\Services\CustomerClientLinkOperation;
use Google\Ads\GoogleAds\V18\Services\CustomerManagerLinkOperation; use Google\Ads\GoogleAds\V18\Services\CustomerManagerLinkOperation;
use Google\Ads\GoogleAds\V18\Services\ListAccessibleCustomersRequest;
use Google\Ads\GoogleAds\V18\Services\MutateCustomerClientLinkRequest; use Google\Ads\GoogleAds\V18\Services\MutateCustomerClientLinkRequest;
use Google\Ads\GoogleAds\V18\Services\MutateCustomerManagerLinkRequest; use Google\Ads\GoogleAds\V18\Services\MutateCustomerManagerLinkRequest;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest; use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
use Google\ApiCore\ApiException; use Google\ApiCore\ApiException;
class GoogleAdsAccountService class GoogleAdsAccountService extends BaseService
{ {
// private $googleAdsClient; // private $googleAdsClient;
// private $customerId; // private $customerId;
// private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1; // private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1;
private $loginCustomerId; // 增加 login-customer-id 属性 // private $loginCustomerId; // 增加 login-customer-id 属性
// Stores the mapping from the root customer IDs (the ones that will be used as a start point
// for printing each hierarchy) to their `CustomerClient` objects.
private static array $rootCustomerClients = []; //必须在入口初始化空数组
public function __construct() public function __construct()
{ {
@ -44,36 +54,6 @@ class GoogleAdsAccountService
// ->build(); // ->build();
} }
/**
* Runs the example.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
*/
// [START list_accessible_customers]
public static function runListAccessibleCustomers()
{
// Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = self::createGoogleAdsClient(0);
$customerServiceClient = $googleAdsClient->getCustomerServiceClient();
// Issues a request for listing all accessible customers.
$accessibleCustomers =
$customerServiceClient->listAccessibleCustomers(new ListAccessibleCustomersRequest());
print 'Total results: ' . count($accessibleCustomers->getResourceNames()) . PHP_EOL;
$resourceNameArray = [];
// Iterates over all accessible customers' resource names and prints them.
foreach ($accessibleCustomers->getResourceNames() as $resourceName) {
/** @var string $resourceName */
printf("Customer resource name: '%s'%s", $resourceName, PHP_EOL);
$resourceNameArray[] = $resourceName;
}
return $resourceNameArray;
}
// [END list_accessible_customers]
/** /**
* Runs the example. * Runs the example.
* *
@ -121,14 +101,14 @@ class GoogleAdsAccountService
* @param int $clientCustomerId the customer ID * @param int $clientCustomerId the customer ID
* @return string the resource name of the customer client link created for the invitation * @return string the resource name of the customer client link created for the invitation
*/ */
private static function createInvitation( public function createInvitation(
int $managerCustomerId, int $managerCustomerId,
int $clientCustomerId int $clientCustomerId
) )
{ {
// Creates a client with the manager customer ID as login customer ID. // Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = self::createGoogleAdsClient($managerCustomerId); $googleAdsClient = $this->createGoogleAdsClient($managerCustomerId);
// Creates a customer client link. // Creates a customer client link.
$customerClientLink = new CustomerClientLink([ $customerClientLink = new CustomerClientLink([
@ -173,14 +153,14 @@ class GoogleAdsAccountService
* @param string $customerClientLinkResourceName the customer client link resource name * @param string $customerClientLinkResourceName the customer client link resource name
* @return string the manager link resource name * @return string the manager link resource name
*/ */
private static function getManagerLinkResourceName( public function getManagerLinkResourceName(
int $managerCustomerId, int $managerCustomerId,
int $clientCustomerId, int $clientCustomerId,
string $customerClientLinkResourceName string $customerClientLinkResourceName
) )
{ {
// Creates a client with the manager customer ID as login customer ID. // Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = self::createGoogleAdsClient($managerCustomerId); $googleAdsClient = $this->createGoogleAdsClient($managerCustomerId);
// Creates the query. // Creates the query.
$query = "SELECT customer_client_link.manager_link_id FROM customer_client_link" . $query = "SELECT customer_client_link.manager_link_id FROM customer_client_link" .
@ -221,13 +201,13 @@ class GoogleAdsAccountService
* @param int $clientCustomerId the customer ID * @param int $clientCustomerId the customer ID
* @param string $managerLinkResourceName the resource name of the manager link to accept * @param string $managerLinkResourceName the resource name of the manager link to accept
*/ */
private static function acceptInvitation( public function acceptInvitation(
int $clientCustomerId, int $clientCustomerId,
string $managerLinkResourceName string $managerLinkResourceName
) )
{ {
// Creates a client with the client customer ID as login customer ID. // Creates a client with the client customer ID as login customer ID.
$googleAdsClient = self::createGoogleAdsClient($clientCustomerId); $googleAdsClient = $this->createGoogleAdsClient($clientCustomerId);
// Creates the customer manager link with the updated status. // Creates the customer manager link with the updated status.
$customerManagerLink = new CustomerManagerLink(); $customerManagerLink = new CustomerManagerLink();
@ -266,18 +246,18 @@ class GoogleAdsAccountService
* Creates a Google Ads client based on the default configuration file * Creates a Google Ads client based on the default configuration file
* and a given login customer id. * and a given login customer id.
* *
* @param int $loginCustomerId the login customer ID * @param int $thirdUserId thirdUser
* @return GoogleAdsClient the created client * @return GoogleAdsClient the created client
*/ */
private static function createGoogleAdsClient(int $loginCustomerId) // public function createGoogleAdsClient(int $thirdUserId)
public function createGoogleAdsClient($refreshToken)
{ {
$advertiserId = getenv('GOOGLE_ADS_CUSTOMER_ID');
// 从数据库获取 access_token // 从数据库获取 access_token
$refreshToken = self::getRefreshTokenFromDatabase($advertiserId); // $refreshToken = $this->getRefreshTokenFromDatabase($thirdUserId);
if (!$refreshToken) { if (!$refreshToken) {
throw new \Exception("Access token not found for advertiserId: " . $advertiserId); throw new \Exception("Access token not found for advertiserId: " . $refreshToken);
} }
// OAuth2 Token Authentication // OAuth2 Token Authentication
@ -286,46 +266,351 @@ class GoogleAdsAccountService
->withRefreshToken($refreshToken) // 使用动态获取的 access_token ->withRefreshToken($refreshToken) // 使用动态获取的 access_token
->build(); ->build();
if ($loginCustomerId > 0) {
// Builds and returns the Google Ads client // Builds and returns the Google Ads client
return ( return (new GoogleAdsClientBuilder())
new GoogleAdsClientBuilder()) // Sets the properties based on the default properties file
// Sets the properties based on the default properties file ->fromFile()
->fromFile() // eUses the OAuth2 credentials crated above.
// eUses the OAuth2 credentials crated above. ->withOAuth2Credential($oAuth2Credential)
->withOAuth2Credential($oAuth2Credential) // Overrides the login customer ID with the given one.
// Overrides the login customer ID with the given one. ->build();
->withLoginCustomerId($loginCustomerId)
->build();
}
/**
* Creates a Google Ads client based on the default configuration file
* and a given login customer id.
*
* @param int $loginCustomerId the login customer ID
* @return GoogleAdsClient the created client
*/
// public function createGoogleAdsClientWithloginCustomerId(int $thirdUserId,int $loginCustomerId)
public function createGoogleAdsClientWithloginCustomerId($refreshToken,int $loginCustomerId)
{
// $advertiserId = getenv('GOOGLE_ADS_CUSTOMER_ID');
// 从数据库获取 access_token
// $refreshToken = $this->getRefreshTokenFromDatabase($thirdUserId);
if (!$refreshToken) {
throw new \Exception("Access token not found for advertiserId: " . $refreshToken);
}
// OAuth2 Token Authentication
$oAuth2Credential = (new OAuth2TokenBuilder())
->fromFile() // 如果需要从文件获取其他配置,可以继续使用 fromFile()
->withRefreshToken($refreshToken) // 使用动态获取的 access_token
->build();
// Builds and returns the Google Ads client
return (
new GoogleAdsClientBuilder())
// Sets the properties based on the default properties file
->fromFile()
// eUses the OAuth2 credentials crated above.
->withOAuth2Credential($oAuth2Credential)
// Overrides the login customer ID with the given one.
->withLoginCustomerId($loginCustomerId)
->build();
}
/**
* Runs the example.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
*/
// [START list_accessible_customers]
public function runListAccessibleCustomers($option)
{
// $loginCustomerId = $option['customer_id'];
$refreshToken = $option['refresh_token'];
// Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = $this->createGoogleAdsClient($refreshToken);
$customerServiceClient = $googleAdsClient->getCustomerServiceClient();
// Issues a request for listing all accessible customers.
$accessibleCustomers =
$customerServiceClient->listAccessibleCustomers(new ListAccessibleCustomersRequest());
print 'Total results: ' . count($accessibleCustomers->getResourceNames()) . PHP_EOL;
$resourceNameArray = [];
// Iterates over all accessible customers' resource names and prints them.
foreach ($accessibleCustomers->getResourceNames() as $resourceName) {
/** @var string $resourceName */
printf("Customer resource name: '%s'%s", $resourceName, PHP_EOL);
$resourceNameArray[] = $resourceName;
}
return $resourceNameArray;
}
// [END list_accessible_customers]
/**
* 层级账号信息
*
*/
public function runGetAccountHierarchy(
$option
)
{
self::$rootCustomerClients = []; //初始化静态变量
$managerCustomerId = isset($option['manager_customer_id'])?(int)$option['manager_customer_id']: null;
$loginCustomerId = isset($option['login_customer_id'])?(int)$option['login_customer_id']: null;
$refreshToken = isset($option['refresh_token'])?$option['refresh_token']: null;
// $thirdUserId = (int)$option['third_user_id'];
// Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = $this->createGoogleAdsClient($refreshToken);
// $customerServiceClient = $googleAdsClient->getCustomerServiceClient();
$rootCustomerIds = [];
if (is_null($managerCustomerId)) {
// We will get the account hierarchies for all accessible customers.
$rootCustomerIds = $this->getAccessibleCustomers($googleAdsClient);
} else { } else {
// Builds and returns the Google Ads client // We will get only the hierarchy for the provided manager customer ID when it's
return (new GoogleAdsClientBuilder()) // provided.
// Sets the properties based on the default properties file $rootCustomerIds[] = $managerCustomerId;
->fromFile()
// eUses the OAuth2 credentials crated above.
->withOAuth2Credential($oAuth2Credential)
// Overrides the login customer ID with the given one.
->build();
} }
$allHierarchies = [];
$accountsWithNoInfo = [];
// Constructs a map of account hierarchies.
foreach ($rootCustomerIds as $rootCustomerId) {
$customerClientToHierarchy =
$this->createCustomerClientToHierarchy($refreshToken,$loginCustomerId, $rootCustomerId);
if (is_null($customerClientToHierarchy)) {
$accountsWithNoInfo[] = $rootCustomerId;
} else {
$allHierarchies += $customerClientToHierarchy;
}
}
// Prints the IDs of any accounts that did not produce hierarchy information.
if (!empty($accountsWithNoInfo)) {
print
'Unable to retrieve information for the following accounts which are likely '
. 'either test accounts or accounts with setup issues. Please check the logs for '
. 'details:' . PHP_EOL;
foreach ($accountsWithNoInfo as $accountId) {
print $accountId . PHP_EOL;
}
print PHP_EOL;
}
$allAccounts = [];
// Prints the hierarchy information for all accounts for which there is hierarchy info
// available.
foreach ($allHierarchies as $rootCustomerId => $customerIdsToChildAccounts) {
// printf(
// "The hierarchy of customer ID %d is printed below:%s",
// $rootCustomerId,
// PHP_EOL
// );
// 获取所有账户的数组(包括根账户及其子账户)
$accounts = [];
self::getAccountHierarchy(
self::$rootCustomerClients[$rootCustomerId],
$customerIdsToChildAccounts,
0,
$accounts);
$allAccounts[$rootCustomerId] = $accounts;
// self::printAccountHierarchy(
// self::$rootCustomerClients[$rootCustomerId],
// $customerIdsToChildAccounts,
// 0
// );
// print PHP_EOL;
}
// dump($allAccounts);
return $allAccounts;
} }
/**
// 从数据库动态获取 google RefreshToken * Creates a map between a customer client and each of its managers' mappings.
private function getRefreshTokenFromDatabase($advertiserId) *
* @param int|null $loginCustomerId the login customer ID used to create the GoogleAdsClient
* @param int $rootCustomerId the ID of the customer at the root of the tree
* @return array|null a map between a customer client and each of its managers' mappings if the
* account hierarchy can be retrieved. If the account hierarchy cannot be retrieved, returns
* null
*/
public function createCustomerClientToHierarchy(
string $refreshToken,
?int $loginCustomerId,
int $rootCustomerId
): ?array
{ {
// 使用 ThinkDb 进行联表查询
// $advertiserId = 'your-advertiser-id'; // 假设你已经获得了广告商ID
$user = ThinkDb::table('bps.bps_third_user_advertiser as a')
->join('bps_third_user as u', 'a.doc_ = u.id', 'left') // 连接 bps_third_user 表
->where('a.advertiser_id', $advertiserId)
->select('u.access_token') // 只选择 access_token 字段
->first();
return $user ? $user->access_token : null; // Creates a client with the manager customer ID as login customer ID.
$googleAdsClient = $this->createGoogleAdsClientWithloginCustomerId($refreshToken,$loginCustomerId ?? $rootCustomerId);
// Creates the Google Ads Service client.
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates a query that retrieves all child accounts of the manager specified in search
// calls below.
$query = 'SELECT customer_client.client_customer, customer_client.level,'
. ' customer_client.manager, customer_client.descriptive_name,'
. ' customer_client.currency_code, customer_client.time_zone,'
. ' customer_client.id FROM customer_client WHERE customer_client.level <= 1';
$rootCustomerClient = null;
// Adds the root customer ID to the list of IDs to be processed.
$managerCustomerIdsToSearch = [$rootCustomerId];
// Performs a breadth-first search algorithm to build an associative array mapping
// managers to their child accounts ($customerIdsToChildAccounts).
$customerIdsToChildAccounts = [];
while (!empty($managerCustomerIdsToSearch)) {
$customerIdToSearch = array_shift($managerCustomerIdsToSearch);
// Issues a search request.
/** @var GoogleAdsServerStreamDecorator $stream */
$stream = $googleAdsServiceClient->searchStream(SearchGoogleAdsStreamRequest::build(
$customerIdToSearch,
$query
));
// Iterates over all elements to get all customer clients under the specified customer's
// hierarchy.
foreach ($stream->iterateAllElements() as $googleAdsRow) {
/** @var GoogleAdsRow $googleAdsRow */
$customerClient = $googleAdsRow->getCustomerClient();
// Gets the CustomerClient object for the root customer in the tree.
if ($customerClient->getId() === $rootCustomerId) {
$rootCustomerClient = $customerClient;
self::$rootCustomerClients[$rootCustomerId] = $rootCustomerClient;
}
// The steps below map parent and children accounts. Continue here so that managers
// accounts exclude themselves from the list of their children accounts.
if ($customerClient->getId() === $customerIdToSearch) {
continue;
}
// For all level-1 (direct child) accounts that are a manager account, the above
// query will be run against them to create an associative array of managers to
// their child accounts for printing the hierarchy afterwards.
$customerIdsToChildAccounts[$customerIdToSearch][] = $customerClient;
// Checks if the child account is a manager itself so that it can later be processed
// and added to the map if it hasn't been already.
if ($customerClient->getManager()) {
// A customer can be managed by multiple managers, so to prevent visiting
// the same customer multiple times, we need to check if it's already in the
// map.
$alreadyVisited = array_key_exists(
$customerClient->getId(),
$customerIdsToChildAccounts
);
if (!$alreadyVisited && $customerClient->getLevel() === 1) {
array_push($managerCustomerIdsToSearch, $customerClient->getId());
}
}
}
}
return is_null($rootCustomerClient) ? null
: [$rootCustomerClient->getId() => $customerIdsToChildAccounts];
} }
/**
* Retrieves a list of accessible customers with the provided set up credentials.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @return int[] the list of customer IDs
*/
public function getAccessibleCustomers(GoogleAdsClient $googleAdsClient): array
{
$accessibleCustomerIds = [];
// Issues a request for listing all customers accessible by this authenticated Google
// account.
$customerServiceClient = $googleAdsClient->getCustomerServiceClient();
$accessibleCustomers =
$customerServiceClient->listAccessibleCustomers(new ListAccessibleCustomersRequest());
print 'No manager customer ID is specified. The example will print the hierarchies of'
. ' all accessible customer IDs:' . PHP_EOL;
foreach ($accessibleCustomers->getResourceNames() as $customerResourceName) {
$customer = CustomerServiceClient::parseName($customerResourceName)['customer_id'];
print $customer . PHP_EOL;
$accessibleCustomerIds[] = intval($customer);
}
print PHP_EOL;
return $accessibleCustomerIds;
}
/**
* Prints the specified account's hierarchy using recursion.
*
* @param CustomerClient $customerClient the customer client whose info will be printed and
* its child accounts will be processed if it's a manager
* @param array $customerIdsToChildAccounts a map from customer IDs to child
* accounts
* @param int $depth the current depth we are printing from in the
* account hierarchy
*/
private static function printAccountHierarchy(
CustomerClient $customerClient,
array $customerIdsToChildAccounts,
int $depth
)
{
if ($depth === 0) {
print 'Customer ID (Descriptive Name, Currency Code, Time Zone)' . PHP_EOL;
}
$customerId = $customerClient->getId();
print str_repeat('-', $depth * 2);
printf(
" %d ('%s', '%s', '%s')%s",
$customerId,
$customerClient->getDescriptiveName(),
$customerClient->getCurrencyCode(),
$customerClient->getTimeZone(),
PHP_EOL
);
// Recursively call this function for all child accounts of $customerClient.
if (array_key_exists($customerId, $customerIdsToChildAccounts)) {
foreach ($customerIdsToChildAccounts[$customerId] as $childAccount) {
self::printAccountHierarchy($childAccount, $customerIdsToChildAccounts, $depth + 1);
}
}
}
private static function getAccountHierarchy(
CustomerClient $customerClient,
array $customerIdsToChildAccounts,
int $depth,
array &$result = [] // 这里使用引用传递
)
{
// Store the current customer ID and descriptive name in the result array
$customerId = $customerClient->getId();
$result[] = [
'customer_id' => $customerId,
'descriptive_name' => $customerClient->getDescriptiveName(),
];
// Recursively call this function for all child accounts of $customerClient.
if (array_key_exists($customerId, $customerIdsToChildAccounts)) {
foreach ($customerIdsToChildAccounts[$customerId] as $childAccount) {
// Recursively add the child account information
$result = self::getAccountHierarchy($childAccount, $customerIdsToChildAccounts, $depth + 1, $result);
}
}
return $result;
}
} }

View File

@ -70,14 +70,14 @@ class GoogleAdsAdService extends BaseService
* @return mixed * @return mixed
* @throws ApiException * @throws ApiException
*/ */
public function runListAds(int $customerId): mixed public function runListAds(int $customerId,$options): mixed
{ {
// $googleAdsClient = $this->googleAdsClient; // $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($customerId); $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$groupAdsResourceName = self::getAds($googleAdsClient->getGoogleAdsClient(), $customerId); $groupAdsResourceName = self::getAds($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
// dump(json_encode($groupAdsResourceName)); // dump(json_encode($groupAdsResourceName));
if (is_array($groupAdsResourceName)) { if (is_array($groupAdsResourceName)) {
self::saveAds($groupAdsResourceName); self::saveAds($groupAdsResourceName);

View File

@ -33,6 +33,7 @@ use app\util\ArgumentParser;
//use Google\Protobuf\Internal\RepeatedField; //use Google\Protobuf\Internal\RepeatedField;
use DateTime;
use think\facade\Db as ThinkDb; use think\facade\Db as ThinkDb;
use app\model\Ad as AdModel; use app\model\Ad as AdModel;
use app\model\Asset as AssetModel; use app\model\Asset as AssetModel;
@ -76,10 +77,11 @@ class GoogleAdsAssetRelationService extends BaseService
*/ */
public function runListAssetRelations(int $customerId): mixed public function runListAssetRelations(int $customerId): mixed
{ {
// dump($customerId);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$assetsResourceName = self::getAssetRelations($customerId); $assetsResourceName = self::getAssetRelations($customerId);
// dump(json_encode($assetsResourceName)); // dump(json_encode($assetsResourceName));
if (is_array($assetsResourceName)) { if (is_array($assetsResourceName && count($assetsResourceName) > 0)) {
self::saveAssetRelations($assetsResourceName); self::saveAssetRelations($assetsResourceName);
} }
// return $assetsResourceName; // return $assetsResourceName;
@ -142,12 +144,18 @@ class GoogleAdsAssetRelationService extends BaseService
$month = $dateDetails['month']; $month = $dateDetails['month'];
$season = $dateDetails['season']; $season = $dateDetails['season'];
// dump($year, $month, $season);
// 获取所有素材 // 获取所有素材
// $assets = AssetModel::where('asset_type', 4)->select(); //图片素材 // $assets = AssetModel::where('asset_type', 4)->select(); //图片素材
$resourceNames = AssetModel::where('asset_type', 4) $resourceNames = AssetModel::where('asset_type', 4)->where('customer_id', $customerId)
->column('asset_id, resource_name'); ->column('asset_id, resource_name');
if (!$resourceNames) {
return [];
}
// dump($resourceNames);return($resourceNames); // dump($resourceNames);return($resourceNames);
$result = []; $result = [];
foreach ($resourceNames as $resourceName) { foreach ($resourceNames as $resourceName) {
@ -240,17 +248,17 @@ class GoogleAdsAssetRelationService extends BaseService
// 提取年和月 // 提取年和月
$year = (int)$dateObj->format('Y'); $year = (int)$dateObj->format('Y');
$month = (int)$dateObj->format('m'); $month = (int)$dateObj->format('Ym');
// 计算季度 // 计算季度
if ($month >= 1 && $month <= 3) { if ($month >= 1 && $month <= 3) {
$season = (int)$dateObj->format('Ym') . '01'; // Q1 $season = (int)$dateObj->format('Y') . '01'; // Q1
} elseif ($month >= 4 && $month <= 6) { } elseif ($month >= 4 && $month <= 6) {
$season = (int)$dateObj->format('Ym') . '02'; // Q2 $season = (int)$dateObj->format('Y') . '02'; // Q2
} elseif ($month >= 7 && $month <= 9) { } elseif ($month >= 7 && $month <= 9) {
$season = (int)$dateObj->format('Ym') . '03'; // Q3 $season = (int)$dateObj->format('Y') . '03'; // Q3
} else { } else {
$season = (int)$dateObj->format('Ym') . '04'; // Q4 $season = (int)$dateObj->format('Y') . '04'; // Q4
} }
return [ return [
@ -259,476 +267,4 @@ class GoogleAdsAssetRelationService extends BaseService
'season' => $season 'season' => $season
]; ];
} }
/**
* This example updates the CPC bid and status for a given ad group. To get ad groups, run
* GetAdAds.php.
*/
/* @param int $customerId the customer ID
* @param $options
* @return mixed
* @throws ApiException
*/
public function runUpdateAd($options): mixed
{
// $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($options['customer_id']);
// Creates a single shared budget to be used by the campaigns added below.
$resourceNames = self::updateAd($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['group_id'], $options['ad_id'], $options['status']);
return $resourceNames;
}
/**
* Runs the updateAd example.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $adGroupId the ad group ID that the ad group ad belongs to
* @param int $adId the ID of the ad to pause
*/
public static function updateAd(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $adGroupId,
int $adId,
int $status
)
{
// Creates ad group ad resource name.
$adGroupAdResourceName = ResourceNames::forAdGroupAd($customerId, $adGroupId, $adId);
// Creates an ad and sets its status to PAUSED.
$adGroupAd = new AdGroupAd();
$adGroupAd->setResourceName($adGroupAdResourceName);
// $adGroupAd->setStatus(AdGroupAdStatus::PAUSED);
$adGroupAd->setStatus($status);
// Constructs an operation that will pause the ad with the specified resource name,
// using the FieldMasks utility to derive the update mask. This mask tells the Google Ads
// API which attributes of the ad group you want to change.
$adGroupAdOperation = new AdGroupAdOperation();
$adGroupAdOperation->setUpdate($adGroupAd);
$adGroupAdOperation->setUpdateMask(FieldMasks::allSetFieldsOf($adGroupAd));
// Issues a mutate request to pause the ad group ad.
$adGroupAdServiceClient = $googleAdsClient->getAdGroupAdServiceClient();
$response = $adGroupAdServiceClient->mutateAdGroupAds(MutateAdGroupAdsRequest::build(
$customerId,
[$adGroupAdOperation]
));
// Prints the resource name of the paused ad group ad.
/** @var AdGroupAd $pausedAdGroupAd */
$pausedAdGroupAd = $response->getResults()[0];
// printf(
// "Ad group ad with resource name: '%s' is paused.%s",
// $pausedAdGroupAd->getResourceName(),
// PHP_EOL
// );
return $pausedAdGroupAd->getResourceName();
}
/**
* 更新广告状态
*/
public function updateAdStatus(int $customerId, int $adGroupId, int $adId, int $status)
{
// 从数据库获取 Ad
$ad = AdModel::find($adId);
if (!$ad) {
// throw new ValidateException('Ad not found');
return false;
}
// 更新数据库中的状态
// $ad->updateStatus($status);
if ($this->modifyDbAdStatus($adId, $status)) {
// 更新 Google Ads 上的状态
// $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($customerId);
$resourceName = self::updateAd($googleAdsClient->getGoogleAdsClient(), $customerId, $adGroupId, $adId, $status);
return true;
}
return false;
}
/**
* 获取广告状态
*/
public function getAdStatus(int $adId)
{
// 从数据库获取 Ad
$ad = AdModel::find($adId);
if (!$ad) {
// throw new ValidateException('Ad not found');
}
// 返回广告状态
return $ad->getStatusTextAttr(null, $ad->toArray());
}
/**
* 判断广告是否启用
*/
// public function isAdEnabled(int $adId)
// {
// $ad = Ad::find($adId);
// if (!$ad) {
// throw new ValidateException('Ad not found');
// }
//
// return $ad->isEnabled();
// }
/**
* 判断广告是否暂停
*/
// public function isAdPaused(int $adId)
// {
// $ad = Ad::find($adId);
// if (!$ad) {
// throw new ValidateException('Ad not found');
// }
//
// return $ad->isPaused();
// }
/**
* 判断广告是否停止
*/
// public function isAdStopped(int $adId)
// {
// $ad = Ad::find($adId);
// if (!$ad) {
// throw new ValidateException('Ad not found');
// }
//
// return $ad->isStopped();
// }
/**
* This example updates the CPC bid and status for a given ad group. To get ad groups, run
* GetAdAds.php.
*/
/* @param int $customerId the customer ID
* @param $options
* @return mixed
* @throws ApiException
*/
public function runGetResponsiveSearchAds($options): mixed
{
// $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($options['customer_id']);
// Creates a single shared budget to be used by the campaigns added below.
if (!isset($options['group_id'])) {
$options['group_id'] = null;
}
$resourceNames = self::getResponsiveSearchAds($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['group_id']);
return $resourceNames;
}
/**
* 获取指定广告组中未移除的自适应搜索广告。
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int|null $adGroupId the ad group ID for which responsive search ads will be retrieved.
* If `null`, returns from all ad groups
*/
public static function getResponsiveSearchAds(
GoogleAdsClient $googleAdsClient,
int $customerId,
?int $adGroupId
)
{
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates a query that retrieves responsive search ads.
$query =
'SELECT ad_group.id, '
. 'ad_group_ad.ad.id, '
. 'ad_group_ad.ad.responsive_search_ad.headlines, '
. 'ad_group_ad.ad.responsive_search_ad.descriptions, '
. 'ad_group_ad.status '
. 'FROM ad_group_ad '
. 'WHERE ad_group_ad.ad.type = RESPONSIVE_SEARCH_AD '
. 'AND ad_group_ad.status != "REMOVED"';
if (!is_null($adGroupId)) {
$query .= " AND ad_group.id = $adGroupId";
}
// Issues a search request.
$response =
$googleAdsServiceClient->search(SearchGoogleAdsRequest::build($customerId, $query));
// Iterates over all rows in all pages and prints the requested field values for
// the responsive search ad in each row.
$isEmptyResult = true;
$resources = [];
foreach ($response->iterateAllElements() as $googleAdsRow) {
/** @var GoogleAdsRow $googleAdsRow */
$isEmptyResult = false;
$ad = $googleAdsRow->getAdGroupAd()->getAd();
$resource = [];
// printf(
// "Responsive search ad with resource name '%s' and status '%s' was found.%s",
// $ad->getResourceName(),
// AdGroupAdStatus::name($googleAdsRow->getAdGroupAd()->getStatus()),
// PHP_EOL
// );
$resource['resource_name'] = $ad->getResourceName();
$resource['status'] = AdGroupAdStatus::name($googleAdsRow->getAdGroupAd()->getStatus());
$responsiveSearchAdInfo = $ad->getResponsiveSearchAd();
// printf(
// 'Headlines:%1$s%2$sDescriptions:%1$s%3$s%1$s',
// PHP_EOL,
// self::convertAdTextAssetsToString($responsiveSearchAdInfo->getHeadlines()),
// self::convertAdTextAssetsToString($responsiveSearchAdInfo->getDescriptions())
// )
$resource['content'] = sprintf(
'Headlines:%1$s%2$sDescriptions:%1$s%3$s%1$s',
PHP_EOL,
self::convertAdTextAssetsToString($responsiveSearchAdInfo->getHeadlines()),
self::convertAdTextAssetsToString($responsiveSearchAdInfo->getDescriptions())
);
$resources[] = $resource;
}
return $resources;
// if ($isEmptyResult) {
// print 'No responsive search ads were found.' . PHP_EOL;
// }
}
/**
* Converts the list of AdTextAsset objects into a string representation.
*
* @param RepeatedField $assets the list of AdTextAsset objects
* @return string the string representation of the provided list of AdTextAsset objects
*/
private static function convertAdTextAssetsToString(RepeatedField $assets): string
{
$result = '';
foreach ($assets as $asset) {
/** @var AdTextAsset $asset */
$result .= sprintf(
"\t%s pinned to %s.%s",
$asset->getText(),
ServedAssetFieldType::name($asset->getPinnedField()),
PHP_EOL
);
}
return $result;
}
/**
* This example updates the CPC bid and status for a given ad group. To get ad groups, run
* GetAdAds.php.
*/
/* @param int $customerId the customer ID
* @param $options
* @return mixed
* @throws ApiException
*/
public function runUpdateResponsiveSearchAd($options): mixed
{
// $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($options['customer_id']);
// Creates a single shared budget to be used by the campaigns added below.
$resourceName = self::updateResponsiveSearchAd($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['ad_id']);
return $resourceName;
}
/**
* updateResponsiveSearchAd.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $adId the ad ID to update
*/
// [START update_responsive_search_ad]
public static function updateResponsiveSearchAd(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $adId
)
{
// Creates an ad with the specified resource name and other changes.
$ad = new Ad([
'resource_name' => ResourceNames::forAd($customerId, $adId),
'responsive_search_ad' => new ResponsiveSearchAdInfo([
// Update some properties of the responsive search ad.
'headlines' => [
new AdTextAsset([
'text' => 'Cruise to Pluto #' . Helper::getShortPrintableDatetime(),
'pinned_field' => ServedAssetFieldType::HEADLINE_1
]),
new AdTextAsset(['text' => 'Tickets on sale now', 'pinned_field' => ServedAssetFieldType::HEADLINE_2]),
new AdTextAsset(['text' => 'Buy your ticket now'])
],
'descriptions' => [
new AdTextAsset(['text' => 'Best space cruise ever.']),
new AdTextAsset([
'text' => 'The most wonderful space experience you will ever have.'])
]
]),
'final_urls' => ['http://www.baidu.com'],
'final_mobile_urls' => ['http://www.baidu.com/mobile']
]);
// Constructs an operation that will update the ad, using the FieldMasks to derive the
// update mask. This mask tells the Google Ads API which attributes of the ad you want to
// change.
$adOperation = new AdOperation();
$adOperation->setUpdate($ad);
$adOperation->setUpdateMask(FieldMasks::allSetFieldsOf($ad));
// Issues a mutate request to update the ad.
$adServiceClient = $googleAdsClient->getAdServiceClient();
$response =
$adServiceClient->mutateAds(MutateAdsRequest::build($customerId, [$adOperation]));
// Prints the resource name of the updated ad.
/** @var Ad $updatedAd */
$updatedAd = $response->getResults()[0];
printf(
"Updated ad with resource name: '%s'.%s",
$updatedAd->getResourceName(),
PHP_EOL
);
return $updatedAd->getResourceName();
}
// [END update_responsive_search_ad]
/**
* 根据给定的前缀搜索 Google Ads 字段检索到关于这些字段的元数据metadata
*/
/* @param int $customerId the customer ID
* @param $options
* @return mixed
* @throws ApiException
*/
public function runSearchForGoogleAdsFields($options): mixed
{
// $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($options['customer_id']);
// Creates a single shared budget to be used by the campaigns added below.
$googleAdsFieldData = self::searchForGoogleAdsFields($googleAdsClient->getGoogleAdsClient(), $options['name_prefix']);
return $googleAdsFieldData;
}
/**
* Runs the example SearchForGoogleAdsFields.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param string $namePrefix the name prefix to use in the query
*/
public static function searchForGoogleAdsFields(GoogleAdsClient $googleAdsClient, string $namePrefix)
{
$googleAdsFieldServiceClient = $googleAdsClient->getGoogleAdsFieldServiceClient();
// Searches for all fields whose name begins with the specified namePrefix.
// A single "%" is the wildcard token in the Google Ads Query language.
$query = "SELECT name, category, selectable, filterable, sortable, selectable_with, "
. "data_type, is_repeated WHERE name LIKE '$namePrefix%'";
$response = $googleAdsFieldServiceClient->searchGoogleAdsFields(
SearchGoogleAdsFieldsRequest::build($query)
);
if (iterator_count($response->getIterator()) === 0) {
printf(
"No GoogleAdsFields found with a name that begins with %s.%s",
$namePrefix,
PHP_EOL
);
return;
}
// Iterates over all rows and prints our the metadata of each matching GoogleAdsField.
foreach ($response->iterateAllElements() as $googleAdsField) {
/** @var GoogleAdsField $googleAdsField */
$fieldInfo = [
'name' => $googleAdsField->getName(),
'category' => GoogleAdsFieldCategory::name($googleAdsField->getCategory()),
'data_type' => GoogleAdsFieldDataType::name($googleAdsField->getDataType()),
'selectable' => $googleAdsField->getSelectable() ? 'true' : 'false',
'filterable' => $googleAdsField->getFilterable() ? 'true' : 'false',
'sortable' => $googleAdsField->getSortable() ? 'true' : 'false',
'repeated' => $googleAdsField->getIsRepeated() ? 'true' : 'false',
'selectable_with' => []
];
// Check if there are fields that are selectable with the current field
if ($googleAdsField->getSelectableWith()->count() > 0) {
$selectableWithFields = iterator_to_array($googleAdsField->getSelectableWith()->getIterator());
sort($selectableWithFields); // Sort the fields alphabetically
$fieldInfo['selectable_with'] = $selectableWithFields;
}
// Add the field info to the result array
$googleAdsFieldData[] = $fieldInfo;
//
// printf("%s:%s", $googleAdsField->getName(), PHP_EOL);
// printf(
// " %-16s: %s%s",
// "category:",
// GoogleAdsFieldCategory::name($googleAdsField->getCategory()),
// PHP_EOL
// );
// printf(
// " %-16s: %s%s",
// "data type:",
// GoogleAdsFieldDataType::name($googleAdsField->getDataType()),
// PHP_EOL
// );
// printf(
// " %-16s: %s%s",
// "selectable:",
// $googleAdsField->getSelectable() ? 'true' : 'false',
// PHP_EOL
// );
// printf(
// " %-16s: %s%s",
// "filterable:",
// $googleAdsField->getFilterable() ? 'true' : 'false',
// PHP_EOL
// );
// printf(
// " %-16s: %s%s",
// "sortable:",
// $googleAdsField->getSortable() ? 'true' : 'false',
// PHP_EOL
// );
// printf(
// " %-16s: %s%s",
// "repeated:",
// $googleAdsField->getIsRepeated() ? 'true' : 'false',
// PHP_EOL
// );
//
// if ($googleAdsField->getSelectableWith()->count() > 0) {
// // Prints the list of fields that are selectable with the field.
// $selectableWithFields =
// iterator_to_array($googleAdsField->getSelectableWith()->getIterator());
// // Sorts and then prints the list.
// sort($selectableWithFields);
// print ' selectable with:' . PHP_EOL;
// foreach ($selectableWithFields as $selectableWithField) {
// /** @var string $selectableWithField */
// printf(" $selectableWithField%s", PHP_EOL);
// }
// }
}
return $googleAdsFieldData; // Return the result array
}
} }

View File

@ -70,12 +70,12 @@ class GoogleAdsAssetService extends BaseService
* @return mixed * @return mixed
* @throws ApiException * @throws ApiException
*/ */
public function runListAssets(int $customerId): mixed public function runListAssets(int $customerId,$options): mixed
{ {
$googleAdsClient = new GoogleAdsClientService($customerId); $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$assetsResourceName = self::getAssets($googleAdsClient->getGoogleAdsClient(), $customerId); $assetsResourceName = self::getAssets($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
// dump(json_encode($assetsResourceName)); // dump(json_encode($assetsResourceName));
if (is_array($assetsResourceName)) { if (is_array($assetsResourceName)) {
self::saveAssets($assetsResourceName); self::saveAssets($assetsResourceName);

View File

@ -40,7 +40,7 @@ class GoogleAdsCampaignService extends BaseService
private $customerId; private $customerId;
private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1; private const NUMBER_OF_CAMPAIGNS_TO_ADD = 1;
public function __construct($customerId = null,GoogleAdsClientService $googleAdsClientService = null) public function __construct($customerId = null, GoogleAdsClientService $googleAdsClientService = null)
{ {
// 使用 GoogleAdsClientService 来初始化 googleAdsClient // 使用 GoogleAdsClientService 来初始化 googleAdsClient
// $googleAdsClient = new GoogleAdsClientService($customerId); // $googleAdsClient = new GoogleAdsClientService($customerId);
@ -75,7 +75,7 @@ class GoogleAdsCampaignService extends BaseService
*/ */
public function runAddCampaign(int $customerId, $options): mixed public function runAddCampaign(int $customerId, $options): mixed
{ {
$googleAdsClient = new GoogleAdsClientService($customerId); $googleAdsClient = new GoogleAdsClientService($options['refresh_token']);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$budgetResourceName = self::addCampaignBudget($googleAdsClient->getGoogleAdsClient(), $customerId, $options); $budgetResourceName = self::addCampaignBudget($googleAdsClient->getGoogleAdsClient(), $customerId, $options);
@ -199,13 +199,11 @@ class GoogleAdsCampaignService extends BaseService
* @return mixed * @return mixed
* @throws ApiException * @throws ApiException
*/ */
public function runListCampaigns(int $customerId): mixed public function runListCampaigns(int $customerId, $options): mixed
{ {
// $googleAdsClient = $this->googleAdsClient; $googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
$googleAdsClient = new GoogleAdsClientService($customerId); $campaignsResourceName = self::getCampaigns($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
// Creates a single shared budget to be used by the campaigns added below.
$campaignsResourceName = self::getCampaigns($googleAdsClient->getGoogleAdsClient(), $customerId);
// dump(json_encode($campaignsResourceName)); // dump(json_encode($campaignsResourceName));
if (is_array($campaignsResourceName)) { if (is_array($campaignsResourceName)) {
self::saveCampaigns($campaignsResourceName); self::saveCampaigns($campaignsResourceName);
@ -304,12 +302,12 @@ class GoogleAdsCampaignService extends BaseService
public static function getDateDatas(GoogleAdsClient $googleAdsClient, int $customerId, $date = '2024-12-19') public static function getDateDatas(GoogleAdsClient $googleAdsClient, int $customerId, $date = '2024-12-19')
{ {
// 调用私有方法提取 year, month, season // 调用私有方法提取 year, month, season
$dateDetails = self::extractDateDetails($date); $dateDetails = self::extractDateDetails($date);
$year = $dateDetails['year']; $year = $dateDetails['year'];
$month = $dateDetails['month']; $month = $dateDetails['month'];
$season = $dateDetails['season']; $season = $dateDetails['season'];
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient(); $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
@ -339,12 +337,11 @@ class GoogleAdsCampaignService extends BaseService
$resourceName['conversions_value'] = $googleAdsRow->getMetrics()->getConversionsValue(); $resourceName['conversions_value'] = $googleAdsRow->getMetrics()->getConversionsValue();
$resourceName['impressions'] = $googleAdsRow->getMetrics()->getImpressions(); $resourceName['impressions'] = $googleAdsRow->getMetrics()->getImpressions();
$resourceName['date'] = $date; $resourceName['date'] = $date;
$resourceName['month'] = $month; $resourceName['month'] = $month;
$resourceName['season'] = $season; $resourceName['season'] = $season;
$resourceName['year'] = $year; $resourceName['year'] = $year;
// $resourceName['budget_id'] = $googleAdsRow->getCampaignBudget()->getId(); // $resourceName['budget_id'] = $googleAdsRow->getCampaignBudget()->getId();
$resourceNames[] = $resourceName; $resourceNames[] = $resourceName;
} }
@ -363,18 +360,18 @@ class GoogleAdsCampaignService extends BaseService
$dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象 $dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象
// 提取年和月 // 提取年和月
$year = (int) $dateObj->format('Y'); $year = (int)$dateObj->format('Y');
$month = (int) $dateObj->format('m'); $month = (int)$dateObj->format('m');
// 计算季度 // 计算季度
if ($month >= 1 && $month <= 3) { if ($month >= 1 && $month <= 3) {
$season = (int) $dateObj->format('Ym') . '01'; // Q1 $season = (int)$dateObj->format('Ym') . '01'; // Q1
} elseif ($month >= 4 && $month <= 6) { } elseif ($month >= 4 && $month <= 6) {
$season = (int) $dateObj->format('Ym') . '02'; // Q2 $season = (int)$dateObj->format('Ym') . '02'; // Q2
} elseif ($month >= 7 && $month <= 9) { } elseif ($month >= 7 && $month <= 9) {
$season = (int) $dateObj->format('Ym') . '03'; // Q3 $season = (int)$dateObj->format('Ym') . '03'; // Q3
} else { } else {
$season = (int) $dateObj->format('Ym') . '04'; // Q4 $season = (int)$dateObj->format('Ym') . '04'; // Q4
} }
return [ return [

View File

@ -5,25 +5,27 @@ namespace app\service;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder; use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException; use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder; use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
// GoogleAdsClientService.php // GoogleAdsClientService.php
class GoogleAdsClientService extends BaseService class GoogleAdsClientService extends BaseService
{ {
private $googleAdsClient; private $googleAdsClient;
private $googleAdsClientWithloginCustomerId;
public function __construct($customerId = null) public function __construct($refreshToken = null, $loginCustomerId = null)
{ {
// 如果没有传入 customerId则从环境变量中获取 // 如果没有传入 customerId则从环境变量中获取
if ($customerId) { // if ($customerId) {
$this->customerId = $customerId; // $this->customerId = $customerId;
} else { // } else {
$this->customerId = getenv('GOOGLE_ADS_CUSTOMER_ID'); // $this->customerId = getenv('GOOGLE_ADS_CUSTOMER_ID');
} // }
// 从数据库获取 refreshToken // 从数据库获取 refreshToken
$refreshToken = $this->getRefreshTokenFromDatabase($this->customerId); // $refreshToken = $this->getRefreshTokenFromDatabase($this->customerId);
if (!$refreshToken) { if (!$refreshToken) {
throw new \Exception("Access token not found for customerId: " . $this->customerId); throw new \Exception("Access token not found for customerId: " . $refreshToken);
} }
// OAuth2 Token Authentication // OAuth2 Token Authentication
@ -33,10 +35,19 @@ class GoogleAdsClientService extends BaseService
->build(); ->build();
// 初始化 Google Ads Client // 初始化 Google Ads Client
$this->googleAdsClient = (new GoogleAdsClientBuilder()) if ($loginCustomerId) {
->fromFile() $this->googleAdsClientWithloginCustomerId = (new GoogleAdsClientBuilder())
->withOAuth2Credential($oAuth2Credential) ->fromFile()
->build(); ->withOAuth2Credential($oAuth2Credential)
->withLoginCustomerId($loginCustomerId)
->build();
} else {
$this->googleAdsClient = (new GoogleAdsClientBuilder())
->fromFile()
->withOAuth2Credential($oAuth2Credential)
->build();
}
} }
@ -45,4 +56,9 @@ class GoogleAdsClientService extends BaseService
return $this->googleAdsClient; return $this->googleAdsClient;
} }
public function getGoogleAdsClientWithloginCustomerId()
{
return $this->googleAdsClientWithloginCustomerId;
}
} }

View File

@ -58,13 +58,14 @@ class GoogleAdsGroupService extends BaseService
* @return mixed * @return mixed
* @throws ApiException * @throws ApiException
*/ */
public function runListGroups(int $customerId): mixed public function runListGroups(int $customerId, $options): mixed
{ {
// $googleAdsClient = $this->googleAdsClient; // $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($customerId); // dump($customerId,$options['refresh_token']);
$googleAdsClient = new GoogleAdsClientService($options['refresh_token'],$options['login_customer_id']);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$groupsResourceName = self::getGroups($googleAdsClient->getGoogleAdsClient(), $customerId); $groupsResourceName = self::getGroups($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
// dump(json_encode($groupsResourceName)); // dump(json_encode($groupsResourceName));
if (is_array($groupsResourceName)) { if (is_array($groupsResourceName)) {
self::saveGroups($groupsResourceName); self::saveGroups($groupsResourceName);
@ -169,7 +170,7 @@ class GoogleAdsGroupService extends BaseService
public function runAddGroup($options): mixed public function runAddGroup($options): mixed
{ {
// $googleAdsClient = $this->googleAdsClient; // $googleAdsClient = $this->googleAdsClient;
$googleAdsClient = new GoogleAdsClientService($customerId); $googleAdsClient = new GoogleAdsClientService($options['refresh_token']);
// Creates a single shared budget to be used by the campaigns added below. // Creates a single shared budget to be used by the campaigns added below.
$resourceNames = self::addGroup($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id']); $resourceNames = self::addGroup($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id']);

View File

@ -5,10 +5,11 @@ namespace app\service;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use think\facade\Db as ThinkDb; use think\facade\Db as ThinkDb;
use app\model\ThirdUserAdvertiser; use app\model\ThirdUserAdvertiser;
use app\model\ThirdUser;
class GoogleOAuthService class GoogleOAuthService
{ {
public function getAuthUrl() public function getAuthUrl($state = '')
{ {
$clientId = getenv('GOOGLE_CLIENT_ID'); $clientId = getenv('GOOGLE_CLIENT_ID');
$redirectUri = getenv('GOOGLE_REDIRECT_URI'); $redirectUri = getenv('GOOGLE_REDIRECT_URI');
@ -17,17 +18,30 @@ class GoogleOAuthService
$accessType = 'offline'; $accessType = 'offline';
// $state = 'state_parameter_passthrough_value'; // 可选保护防止CSRF // $state = 'state_parameter_passthrough_value'; // 可选保护防止CSRF
// 生成随机的state参数防止CSRF攻击
// $state = bin2hex(random_bytes(16)); // 生成一个随机字符串
// 将state保存到会话或数据库中稍后验证 // 将state保存到会话或数据库中稍后验证
// $_SESSION['oauth_state'] = $state; // 使用PHP会话来保存state // $_SESSION['oauth_state'] = $state; // 使用PHP会话来保存state
// $authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&state=$state"; // $authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&state=$state";
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType"; if (!empty($state)) {
// 生成随机的state参数防止CSRF攻击
// $state = bin2hex(random_bytes(16)); // 生成一个随机字符串
// $this->saveThirdUser($state);
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType&state=$state";
} else {
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType";
}
return $authUrl; return $authUrl;
} }
public function getThirdUserByRandomCode($state)
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$result = ThinkDb::name($tableName)->where('random_code', $state)->find();
return $result;
}
public function getRefreshToken($authCode) public function getRefreshToken($authCode)
{ {
@ -45,7 +59,94 @@ class GoogleOAuthService
return json_decode($response->getBody(), true); return json_decode($response->getBody(), true);
} }
public function saveRefreshToken($refreshToken, $accessToken) public function saveThirdUser($state)
{
//发起授权前新记录到bps_third_user表
$data = [
'random_code' => $state,
'is_default' => 't',
'third_type' => 'google',
];
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = " INSERT INTO {$tableName}
(random_code, is_default, third_type)
VALUES (:random_code, :is_default, :third_type";
ThinkDb::execute($sql, $data);
}
public function getCustomerList($third_user_id = 0)
{
$tableName = 'bps_third_user_advertiser';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = "SELECT * FROM {$tableName} WHERE doc_ = :third_user_id";
$data = ['third_user_id' => $third_user_id];
return ThinkDb::query($sql, $data);
}
//保存或更新某个主体部广告账号
public function saveThirdUserAdvertiser($customer_id, $third_user_id,$login_customer_id,$customer_name = '')
{
// 确保 customer_id 和 third_user_id 是字符串
$customer_id = (string) $customer_id;
$tableName = 'bps_third_user_advertiser';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'doc_' => $third_user_id,
'advertiser_id' => $customer_id,
'advertiser_name' => $customer_name,
'google_login_customer_id' => $login_customer_id,
];
$sql = "
INSERT INTO {$tableName}
(advertiser_id,advertiser_name, doc_,google_login_customer_id)
VALUES (:advertiser_id, :advertiser_name,:doc_,:google_login_customer_id)
ON CONFLICT (advertiser_id,doc_)
DO UPDATE SET
advertiser_name = EXCLUDED.advertiser_name,
google_login_customer_id = EXCLUDED.google_login_customer_id
";
// dump($sql,$data);
ThinkDb::execute($sql, $data);
}
//绑定某个主体的广告账号
public function bindThirdUserAdvertiser($customer_id, $third_user_id)
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'id' => $third_user_id,
'user_id' => $customer_id,];
$sql = "
UPDATE {$tableName}
SET user_id = :user_id
WHERE id = :id
";
ThinkDb::execute($sql, $data);
}
public function updateThirdUser($state, $refreshToken): void
{
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$data = [
'access_token' => $refreshToken,
'random_code' => $state,];
$sql = "
UPDATE {$tableName}
SET access_token = :access_token
WHERE random_code = :random_code
";
ThinkDb::execute($sql, $data);
}
public function saveRefreshToken($refreshToken, $state = '')
{ {
// 使用ThinkORM保存数据到bps_third_user表 // 使用ThinkORM保存数据到bps_third_user表
// $thirdUser = new \App\Models\ThirdUser(); // $thirdUser = new \App\Models\ThirdUser();
@ -62,28 +163,35 @@ class GoogleOAuthService
]; ];
$tableName = 'bps_third_user'; $tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName; $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
if (!empty($state)) {
$sql = " $thirdUser = ThirdUser::where('user_id', $state)->find(); // 获取第一个结果
// dump($thirdUser); return ($uid);
if ($thirdUser) {
$data['id'] = $thirdUser->id;
$sql = "
UPDATE {$tableName}
SET
access_token = :access_token,
is_default = :is_default,
third_type = :third_type
WHERE id = :id
";
} else {
$data['user_id'] = $state;
$sql = "
INSERT INTO {$tableName}
(access_token, is_default, third_type, user_id)
VALUES (:access_token, :is_default, :third_type, :user_id)
";
}
} else {
$sql = "
INSERT INTO {$tableName} INSERT INTO {$tableName}
(access_token, is_default, third_type) (access_token, is_default, third_type)
VALUES (:access_token, :is_default, :third_type) VALUES (:access_token, :is_default, :third_type)
ON CONFLICT (user_id)
DO UPDATE SET
access_token = EXCLUDED.access_token,
is_default = EXCLUDED.is_default,
"; ";
// $sql = " }
// INSERT INTO {$tableName}
// (access_token, is_default, random_code, third_type, user_id, facebook_user_id)
// VALUES (:access_token, :is_default, :random_code, :third_type, :user_id, :facebook_user_id)
// ON CONFLICT (user_id)
// DO UPDATE SET
// access_token = EXCLUDED.access_token,
// is_default = EXCLUDED.is_default,
// random_code = EXCLUDED.random_code,
// third_type = EXCLUDED.third_type,
// ";
ThinkDb::execute($sql, $data); ThinkDb::execute($sql, $data);
} }
@ -103,7 +211,7 @@ class GoogleOAuthService
} }
public function revokeToken($accessToken) public function revokeToken($accessToken, $third_user_id)
{ {
$client = new Client(); $client = new Client();
$client->post('https://oauth2.googleapis.com/revoke', [ $client->post('https://oauth2.googleapis.com/revoke', [
@ -113,16 +221,19 @@ class GoogleOAuthService
]); ]);
// 在数据库中删除或标记该`access_token(其实是refresh_token)`为无效 // 在数据库中删除或标记该`access_token(其实是refresh_token)`为无效
// ThirdUserModel::where('access_token', $accessToken)->delete(); ThirdUserAdvertiser::where('doc_', $third_user_id)->delete();
$tableName = "bps.bps_third_user";
$sql = "UPDATE {$tableName} SET access_token = '' WHERE access_token = :access_token";
$data = [ $tableName = 'bps_third_user';
'access_token' => $accessToken // 这里的 $accessToken 是您想要匹配的值 $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
$sql = "UPDATE {$tableName} SET access_token = :access_token WHERE id = :id";
$data = [
'access_token' => '', // 这里的 $accessToken 是您想要匹配的值
'id' => $third_user_id, // 这里的 $accessToken 是您想要匹配的值
]; ];
// 执行 SQL 语句 // 执行 SQL 语句
ThinkDb::execute($sql, $data); $result = ThinkDb::execute($sql, $data);
// ThirdUser::where('access_token', $accessToken)->delete();
} }
public function useRefreshToken($refreshToken) public function useRefreshToken($refreshToken)
@ -152,7 +263,7 @@ class GoogleOAuthService
$customers = ThirdUserAdvertiser::alias('tua') $customers = ThirdUserAdvertiser::alias('tua')
->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表 ->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表
->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录 ->where('tu.third_type', 'google') // 筛选 third_type 为 google 的记录
->field('tua.advertiser_id') // 获取 advertiser_id 字段 ->field('tua.advertiser_id as customer_id,tua.google_login_customer_id as login_customer_id, tu.access_token as refresh_token') // 获取 advertiser_id 字段
->select(); // 执行查询 ->select(); // 执行查询
// 如果没有找到符合条件的广告主,抛出异常 // 如果没有找到符合条件的广告主,抛出异常
@ -162,7 +273,7 @@ class GoogleOAuthService
} }
// 转换为简单的数组(提取 advertiser_id // 转换为简单的数组(提取 advertiser_id
return $customers->column('advertiser_id'); return $customers->toArray();
} }

View File

@ -8,6 +8,7 @@ use app\event\GoogleAdsGroups;
use app\event\GoogleAdsAds; use app\event\GoogleAdsAds;
use app\event\GoogleAdsAssets; use app\event\GoogleAdsAssets;
use app\event\GoogleAdsAssetRelations; use app\event\GoogleAdsAssetRelations;
use app\event\GoogleAdsCustomers;
use app\event\GoogleAdsDateDatas; use app\event\GoogleAdsDateDatas;
@ -40,6 +41,9 @@ return [
GoogleAdsAssetRelations::VIDEOASSET => [ GoogleAdsAssetRelations::VIDEOASSET => [
[GoogleAdsAssetRelations::class, 'getVideoAssetRelations'], [GoogleAdsAssetRelations::class, 'getVideoAssetRelations'],
], ],
GoogleAdsCustomers::CUSTOMERADD => [
[GoogleAdsCustomers::class, 'addCustomers'],
],
]; ];

View File

@ -21,7 +21,7 @@ global $argv;
return [ return [
'webman' => [ 'webman' => [
'handler' => Http::class, 'handler' => Http::class,
'listen' => 'http://0.0.0.0:8042', 'listen' => 'http://0.0.0.0:8045',
'count' => cpu_count() * 4, 'count' => cpu_count() * 4,
'user' => '', 'user' => '',
'group' => '', 'group' => '',

View File

@ -15,6 +15,7 @@
//use app\controller\IndexController; //use app\controller\IndexController;
use app\controller\AdController; use app\controller\AdController;
use app\controller\OAuthController; use app\controller\OAuthController;
use app\controller\CustomerController;
use app\controller\GoogleAdsController; use app\controller\GoogleAdsController;
use support\Request; use support\Request;
use Webman\Route; use Webman\Route;
@ -68,17 +69,25 @@ Route::group('/googleads', function () {
})->middleware([ })->middleware([
app\middleware\OauthCheck::class, app\middleware\OauthCheck::class,
]); ]);
Route::group('/customer', function () {
Route::post('/list', [CustomerController::class, 'getCustomerList']);
Route::post('/bind', [CustomerController::class, 'bindAdvertiser']);
Route::post('/list_resource', [CustomerController::class, 'accessibleCustomers']);
Route::post('/list_tree', [CustomerController::class, 'accountHierarchy']);
})->middleware([
app\middleware\OauthCheck::class,
]);
Route::group('/auth', function () { Route::group('/auth', function () {
Route::get('/code', [OAuthController::class, 'getAuthCode']); Route::get('/code', [OAuthController::class, 'getAuthCode']);
Route::post('/callback', [OAuthController::class, 'handleCallback']); Route::post('/callback', [OAuthController::class, 'handleCallback']);
Route::post('/refresh_token_get', [OAuthController::class, 'getRefreshToken']); Route::post('/refresh_token_get', [OAuthController::class, 'getRefreshToken']);
Route::post('/refresh_token_use', [OAuthController::class, 'useRefreshToken']); Route::post('/refresh_token_use', [OAuthController::class, 'useRefreshToken']);
Route::post('/refresh_token_test', [OAuthController::class, 'testRefreshToken'])->middleware([ Route::post('/refresh_token_test', [OAuthController::class, 'testRefreshToken']);
Route::post('/refresh_token_revoke', [OAuthController::class, 'revokeRefreshToken']);
})->middleware([
app\middleware\Jwt::class, app\middleware\Jwt::class,
]); ]);
Route::post('/refresh_token_revoke', [OAuthController::class, 'revokeRefreshToken']);
});
}); });
@ -128,9 +137,7 @@ Route::group('/googleads', function () {
Route::group('/account_link', function () { Route::group('/account_link', function () {
Route::post('/create', [GoogleAdsController::class, 'createLinkManagerToClient']); Route::post('/create', [GoogleAdsController::class, 'createLinkManagerToClient']);
}); });
Route::group('/account_link', function () {
Route::post('/list', [GoogleAdsController::class, 'accessibleCustomers']);
});
Route::group('/datedata', function () { Route::group('/datedata', function () {
Route::post('/list', [GoogleAdsController::class, 'listDateDatas']); Route::post('/list', [GoogleAdsController::class, 'listDateDatas']);
}); });