实现层级账号及其各层级广告数据更新
This commit is contained in:
parent
01247881b2
commit
14301a08e4
113
app/controller/CustomerController.php
Normal file
113
app/controller/CustomerController.php
Normal 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
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\Campaign as CampaignModel;
|
||||
use app\model\CampaignBudget;
|
||||
use Google\ApiCore\ApiException;
|
||||
use support\Request;
|
||||
use app\service\GoogleAdsCampaignService;
|
||||
@ -12,6 +10,7 @@ use app\service\GoogleAdsAdService;
|
||||
use app\service\GoogleAdsAssetService;
|
||||
use app\service\GoogleAdsAssetRelationService;
|
||||
use app\service\GoogleAdsAccountService;
|
||||
//use app\service\GoogleOAuthService;
|
||||
use support\Response;
|
||||
use DI\Annotation\Inject;
|
||||
use think\facade\Db as ThinkDb;
|
||||
@ -207,12 +206,6 @@ class GoogleAdsController
|
||||
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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联广告客户ID
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function listAccessibleCustomers(): Response
|
||||
{
|
||||
$resourceName = $this->googleAdsAccountService->runListAccessibleCustomers();
|
||||
return $this->successResponse(['links_resource_name' => $resourceName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* get campaigns
|
||||
@ -274,7 +258,7 @@ class GoogleAdsController
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
/**
|
||||
@ -283,7 +267,7 @@ class GoogleAdsController
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,9 @@ use support\Request;
|
||||
use support\Response;
|
||||
use DI\Annotation\Inject;
|
||||
use app\model\ThirdUserAdvertiser;
|
||||
use app\event\GoogleAdsCampaigns;
|
||||
use app\event\GoogleAdsGroups;
|
||||
use app\event\GoogleAdsAds;
|
||||
use app\event\GoogleAdsDateDatas;
|
||||
use app\event\GoogleAdsMaterials;
|
||||
use app\model\ThirdUser;
|
||||
|
||||
use app\event\GoogleAdsCustomers;
|
||||
use Webman\Event\Event;
|
||||
|
||||
class OAuthController
|
||||
@ -24,9 +22,10 @@ class OAuthController
|
||||
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([
|
||||
'url' => $authUrl,
|
||||
]);
|
||||
@ -35,30 +34,36 @@ class OAuthController
|
||||
|
||||
public function handleCallback(Request $request)
|
||||
{
|
||||
// $state = $request->input('state'); // 从Google回调中获取state
|
||||
$state = $request->input('state'); // 从Google回调中获取state
|
||||
$code = $request->input('code'); // 授权码
|
||||
|
||||
// 验证state值是否与保存的值一致
|
||||
// if ($state !== $_SESSION['oauth_state']) {
|
||||
// if ($state !== '7a7a9edad5b48c127b7c14fabe39fae0') {
|
||||
// return $this->errorResponse(400, 'Invalid state parameter');
|
||||
// }
|
||||
if (!$state) {
|
||||
return $this->errorResponse(300, 'Invalid state parameter');
|
||||
}
|
||||
// state值验证通过,继续处理授权码
|
||||
$googleOAuthService = new GoogleOAuthService();
|
||||
|
||||
$tokens = $googleOAuthService->getRefreshToken($code);
|
||||
if (!isset($tokens['refresh_token'])) {
|
||||
return $this->errorResponse(300, 'Invalid state parameter');
|
||||
}else{
|
||||
// 保存refresh token到数据库
|
||||
$googleOAuthService->updateRefreshToken($tokens['refresh_token'], $tokens['access_token']);
|
||||
// 根据新用户绑定插入新数据todo
|
||||
// if(!$result) {
|
||||
// $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $tokens['access_token']);
|
||||
// }
|
||||
|
||||
} else {
|
||||
$googleOAuthService->saveRefreshToken($tokens['refresh_token'], $state);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
||||
|
||||
public function getRefreshToken(Request $request)
|
||||
@ -93,29 +98,50 @@ class OAuthController
|
||||
public function revokeRefreshToken(Request $request)
|
||||
{
|
||||
// $accessToken = $request->input('token'); //access token
|
||||
// $customerId = isset($requestData['ad_customer_id']) ? $requestData['ad_customer_id'] : getenv('GOOGLE_ADS_CUSTOMER_ID');
|
||||
$customerId = getenv('GOOGLE_ADS_CUSTOMER_ID'); //临时指定
|
||||
// $customerId = isset($requestData['customer_id']) ? $requestData['customer_id'] : getenv('GOOGLE_ADS_CUSTOMER_ID');
|
||||
// $customerId = getenv('GOOGLE_ADS_CUSTOMER_ID'); //临时指定
|
||||
|
||||
$uid = $request->input('user_id');
|
||||
|
||||
// 通过 advertiser_id 查询 ThirdUserAdvertiser,联表查询 ThirdUser 数据
|
||||
$userAdvertiser = ThirdUserAdvertiser::with('googleUser') // 联表查询 user 关联
|
||||
->where('advertiser_id', $customerId) // 根据 advertiser_id 查询
|
||||
->find(); // 获取第一个结果
|
||||
$thirdUser = ThirdUser::where('user_id', $uid)->find(); // 获取第一个结果
|
||||
// dump($thirdUser); return ($uid);
|
||||
if (!$thirdUser) {
|
||||
return $this->errorResponse(300, '未授权');
|
||||
}
|
||||
// dump($userAdvertiser->googleUser->access_token);
|
||||
$accessToken = $userAdvertiser->googleUser->access_token;
|
||||
$accessToken = $thirdUser->access_token;
|
||||
|
||||
$googleOAuthService = new GoogleOAuthService();
|
||||
$googleOAuthService->revokeToken($accessToken);
|
||||
$googleOAuthService->revokeToken($accessToken, $thirdUser->id);
|
||||
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)
|
||||
{
|
||||
|
||||
// 接建立socket连到内部推送端口
|
||||
$client = stream_socket_client('tcp://192.168.21.27:22101', $errorCode, $errorMessage);
|
||||
if (false === $client) {
|
||||
throw new \Exception('rpc failed to connect: '.$errorMessage);
|
||||
throw new \Exception('rpc failed to connect: ' . $errorMessage);
|
||||
}
|
||||
$rpc_request = [
|
||||
'class' => 'Auth',
|
||||
@ -128,7 +154,7 @@ class OAuthController
|
||||
]
|
||||
];
|
||||
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
|
||||
fwrite($client, json_encode($rpc_request)."\n");
|
||||
fwrite($client, json_encode($rpc_request) . "\n");
|
||||
// 读取推送结果
|
||||
$result = fgets($client, 10240000);
|
||||
// 解析JSON字符串
|
||||
|
@ -55,9 +55,9 @@ class GoogleAdsAds
|
||||
public function getAds($options)
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsAdService = new GoogleAdsAdService($customerId);
|
||||
$resourceName = $googleAdsAdService->runListAds($customerId);
|
||||
foreach ($customers as $customer) {
|
||||
$googleAdsAdService = new GoogleAdsAdService($customer['customer_id']);
|
||||
$resourceName = $googleAdsAdService->runListAds($customer['customer_id'],$customer);
|
||||
}
|
||||
|
||||
// return $this->successResponse(['ads_list' => $resourceName]);
|
||||
|
@ -56,9 +56,10 @@ class GoogleAdsAssetRelations
|
||||
public function getAssetRelations($options)
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId);
|
||||
$resourceName = $googleAdsAssetRelationService->runListAssetRelations($customerId);
|
||||
foreach ($customers as $customer) {
|
||||
// dump($customer);
|
||||
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customer['customer_id']);
|
||||
$resourceName = $googleAdsAssetRelationService->runListAssetRelations($customer['customer_id']);
|
||||
}
|
||||
|
||||
// return $this->successResponse(['ads_list' => $resourceName]);
|
||||
@ -70,9 +71,9 @@ class GoogleAdsAssetRelations
|
||||
public function getVideoAssetRelations($options)
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId);
|
||||
$resourceName = $googleAdsAssetRelationService->runListVideoAssetRelations($customerId);
|
||||
foreach ($customers as $customer) {
|
||||
$googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customer['customer_id']);
|
||||
$resourceName = $googleAdsAssetRelationService->runListVideoAssetRelations($customer['customer_id']);
|
||||
}
|
||||
|
||||
// return $this->successResponse(['ads_list' => $resourceName]);
|
||||
|
@ -55,9 +55,9 @@ class GoogleAdsAssets
|
||||
public function getAssets($options)
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsAssetService = new GoogleAdsAssetService($customerId);
|
||||
$resourceName = $googleAdsAssetService->runListAssets($customerId);
|
||||
foreach ($customers as $customer) {
|
||||
$googleAdsAssetService = new GoogleAdsAssetService($customer['customer_id']);
|
||||
$resourceName = $googleAdsAssetService->runListAssets($customer['customer_id'],$customer);
|
||||
}
|
||||
|
||||
// return $this->successResponse(['ads_list' => $resourceName]);
|
||||
|
@ -59,9 +59,10 @@ class GoogleAdsCampaigns
|
||||
public function getCampaigns($options)
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsCampaignService = new googleAdsCampaignService($customerId);
|
||||
$resourceName = $googleAdsCampaignService->runListCampaigns($customerId);
|
||||
// dump($customers);
|
||||
foreach ($customers as $customer) {
|
||||
$googleAdsCampaignService = new googleAdsCampaignService($customer['customer_id']);
|
||||
$resourceName = $googleAdsCampaignService->runListCampaigns($customer['customer_id'],$customer);
|
||||
}
|
||||
// return $this->successResponse(['campaigns_list' => $resourceName]);
|
||||
}
|
||||
|
325
app/event/GoogleAdsCustomers.php
Normal file
325
app/event/GoogleAdsCustomers.php
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
@ -58,10 +58,9 @@ class GoogleAdsGroups
|
||||
{
|
||||
$customers = $this->googleOAuthService->getGoogleAdCustomers([]);
|
||||
|
||||
foreach ($customers as $customerId) {
|
||||
$googleAdsGroupService = new GoogleAdsGroupService($customerId);
|
||||
|
||||
$resourceName = $googleAdsGroupService->runListGroups($customerId);
|
||||
foreach ($customers as $customer) {
|
||||
$googleAdsGroupService = new GoogleAdsGroupService($customer['customer_id']);
|
||||
$resourceName = $googleAdsGroupService->runListGroups($customer['customer_id'],$customer);
|
||||
|
||||
// return $this->successResponse(['groups_list' => $resourceName]);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace app\model;
|
||||
|
||||
use think\Model;
|
||||
use app\model\ThirdUserAdvertiser;
|
||||
|
||||
class ThirdUser extends Model
|
||||
{
|
||||
@ -25,4 +26,11 @@ class ThirdUser extends Model
|
||||
{
|
||||
return $this->hasMany(ThirdUserAdvertiser::class, 'doc_', 'id');
|
||||
}
|
||||
|
||||
// 使用 onBeforeDelete 事件来级联删除广告主记录
|
||||
// public static function onBeforeDelete($thirdUser)
|
||||
// {
|
||||
// // 在删除 ThirdUser 时,删除所有与之关联的 ThirdUserAdvertiser 记录
|
||||
// $thirdUser->advertisers()->delete();
|
||||
// }
|
||||
}
|
@ -4,6 +4,7 @@ namespace app\process;
|
||||
|
||||
|
||||
use app\event\GoogleAdsCampaigns;
|
||||
use app\event\GoogleAdsCustomers;
|
||||
use app\event\GoogleAdsGroups;
|
||||
use app\event\GoogleAdsAds;
|
||||
use app\event\GoogleAdsAssets;
|
||||
@ -49,36 +50,36 @@ class UpdateGoogleAdsTask
|
||||
}
|
||||
);
|
||||
// 每15分钟执行一次
|
||||
new Crontab('40 */15 * * * *', function () {
|
||||
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始');
|
||||
// Event::emit(GoogleAdsCampaigns::type, []);
|
||||
new Crontab('15 */10 * * * *', function () {
|
||||
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始');
|
||||
Event::emit(GoogleAdsCampaigns::type, []);
|
||||
}
|
||||
);
|
||||
|
||||
// 每15分钟执行一次
|
||||
new Crontab('50 */15 * * * *', function () {
|
||||
new Crontab('30 */10 * * * *', function () {
|
||||
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsGroups::type . '开始');
|
||||
Event::emit(GoogleAdsGroups::type, []);
|
||||
}
|
||||
);
|
||||
|
||||
// 每15分钟执行一次
|
||||
new Crontab('55 */15 * * * *', function () {
|
||||
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始');
|
||||
// Event::emit(GoogleAdsAds::type, []);
|
||||
new Crontab('5 */11 * * * *', function () {
|
||||
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始');
|
||||
Event::emit(GoogleAdsAds::type, []);
|
||||
}
|
||||
|
||||
);
|
||||
// 每15分钟执行一次
|
||||
new Crontab('25 */15 * * * *', function () {
|
||||
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始');
|
||||
// Event::emit(GoogleAdsAssets::type, []);
|
||||
new Crontab('25 */19 * * * *', function () {
|
||||
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始');
|
||||
Event::emit(GoogleAdsAssets::type, []);
|
||||
}
|
||||
);
|
||||
|
||||
new Crontab('55 */50 * * * *', function () {
|
||||
// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始');
|
||||
// Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []);
|
||||
new Crontab('*/20 * * * * *', function () {
|
||||
dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始');
|
||||
Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []);
|
||||
});
|
||||
|
||||
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分钟执行一次
|
||||
|
@ -2,7 +2,7 @@
|
||||
// app/service/BaseService.php
|
||||
namespace app\service;
|
||||
|
||||
use app\model\ThirdUserAdvertiser;
|
||||
use app\model\ThirdUser;
|
||||
use think\db\exception\BindParamException;
|
||||
use think\facade\Db as ThinkDb;
|
||||
use app\model\Campaign as CampaignModel;
|
||||
@ -84,19 +84,18 @@ class BaseService
|
||||
/**
|
||||
* 从数据库获取 refreshToken
|
||||
*
|
||||
* @param string $advertiserId 广告主ID
|
||||
* @param string $thirdUserId 广告主ID
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRefreshTokenFromDatabase($advertiserId)
|
||||
public function getRefreshTokenFromDatabase($thirdUserId)
|
||||
{
|
||||
// 通过 advertiser_id 查询 ThirdUserAdvertiser,联表查询 ThirdUser 数据
|
||||
$userAdvertiser = ThirdUserAdvertiser::with('googleUser')
|
||||
->where('advertiser_id', $advertiserId)
|
||||
->find();
|
||||
$thirdUser = ThirdUser::find($thirdUserId);
|
||||
//dump($thirdUser);
|
||||
|
||||
// 如果找到广告主数据
|
||||
if ($userAdvertiser && $userAdvertiser->googleUser) {
|
||||
return $userAdvertiser->googleUser->access_token; // 返回 access_token
|
||||
if ($thirdUser) {
|
||||
return $thirdUser->access_token; // 返回 access_token
|
||||
}
|
||||
|
||||
return null; // 如果没有找到,返回 null
|
||||
|
@ -9,26 +9,36 @@ use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
|
||||
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;
|
||||
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder;
|
||||
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\V18\ResourceNames;
|
||||
use Google\Ads\GoogleAds\V18\Enums\ManagerLinkStatusEnum\ManagerLinkStatus;
|
||||
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\CustomerManagerLink;
|
||||
use Google\Ads\GoogleAds\V18\Services\CustomerClientLinkOperation;
|
||||
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\MutateCustomerManagerLinkRequest;
|
||||
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
|
||||
use Google\ApiCore\ApiException;
|
||||
|
||||
class GoogleAdsAccountService
|
||||
class GoogleAdsAccountService extends BaseService
|
||||
{
|
||||
// private $googleAdsClient;
|
||||
// private $customerId;
|
||||
// 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()
|
||||
{
|
||||
@ -44,36 +54,6 @@ class GoogleAdsAccountService
|
||||
// ->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.
|
||||
*
|
||||
@ -121,14 +101,14 @@ class GoogleAdsAccountService
|
||||
* @param int $clientCustomerId the customer ID
|
||||
* @return string the resource name of the customer client link created for the invitation
|
||||
*/
|
||||
private static function createInvitation(
|
||||
public function createInvitation(
|
||||
int $managerCustomerId,
|
||||
int $clientCustomerId
|
||||
)
|
||||
{
|
||||
|
||||
// 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.
|
||||
$customerClientLink = new CustomerClientLink([
|
||||
@ -173,14 +153,14 @@ class GoogleAdsAccountService
|
||||
* @param string $customerClientLinkResourceName the customer client link resource name
|
||||
* @return string the manager link resource name
|
||||
*/
|
||||
private static function getManagerLinkResourceName(
|
||||
public function getManagerLinkResourceName(
|
||||
int $managerCustomerId,
|
||||
int $clientCustomerId,
|
||||
string $customerClientLinkResourceName
|
||||
)
|
||||
{
|
||||
// Creates a client with the manager customer ID as login customer ID.
|
||||
$googleAdsClient = self::createGoogleAdsClient($managerCustomerId);
|
||||
$googleAdsClient = $this->createGoogleAdsClient($managerCustomerId);
|
||||
|
||||
// Creates the query.
|
||||
$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 string $managerLinkResourceName the resource name of the manager link to accept
|
||||
*/
|
||||
private static function acceptInvitation(
|
||||
public function acceptInvitation(
|
||||
int $clientCustomerId,
|
||||
string $managerLinkResourceName
|
||||
)
|
||||
{
|
||||
// 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.
|
||||
$customerManagerLink = new CustomerManagerLink();
|
||||
@ -266,18 +246,18 @@ class GoogleAdsAccountService
|
||||
* Creates a Google Ads client based on the default configuration file
|
||||
* and a given login customer id.
|
||||
*
|
||||
* @param int $loginCustomerId the login customer ID
|
||||
* @param int $thirdUserId thirdUser
|
||||
* @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
|
||||
$refreshToken = self::getRefreshTokenFromDatabase($advertiserId);
|
||||
// $refreshToken = $this->getRefreshTokenFromDatabase($thirdUserId);
|
||||
|
||||
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
|
||||
@ -286,7 +266,43 @@ class GoogleAdsAccountService
|
||||
->withRefreshToken($refreshToken) // 使用动态获取的 access_token
|
||||
->build();
|
||||
|
||||
if ($loginCustomerId > 0) {
|
||||
|
||||
// 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.
|
||||
->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())
|
||||
@ -297,35 +313,304 @@ class GoogleAdsAccountService
|
||||
// Overrides the login customer ID with the given one.
|
||||
->withLoginCustomerId($loginCustomerId)
|
||||
->build();
|
||||
} else {
|
||||
// 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.
|
||||
->build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 从数据库动态获取 google RefreshToken
|
||||
private function getRefreshTokenFromDatabase($advertiserId)
|
||||
/**
|
||||
* Runs the example.
|
||||
*
|
||||
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
|
||||
*/
|
||||
// [START list_accessible_customers]
|
||||
public function runListAccessibleCustomers($option)
|
||||
{
|
||||
// 使用 ThinkDb 进行联表查询
|
||||
// $advertiserId = 'your-advertiser-id'; // 假设你已经获得了广告商ID
|
||||
// $loginCustomerId = $option['customer_id'];
|
||||
$refreshToken = $option['refresh_token'];
|
||||
// Creates a client with the manager customer ID as login customer ID.
|
||||
$googleAdsClient = $this->createGoogleAdsClient($refreshToken);
|
||||
|
||||
$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();
|
||||
$customerServiceClient = $googleAdsClient->getCustomerServiceClient();
|
||||
|
||||
return $user ? $user->access_token : null;
|
||||
// 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 {
|
||||
// We will get only the hierarchy for the provided manager customer ID when it's
|
||||
// provided.
|
||||
$rootCustomerIds[] = $managerCustomerId;
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a map between a customer client and each of its managers' mappings.
|
||||
*
|
||||
* @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
|
||||
{
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -70,14 +70,14 @@ class GoogleAdsAdService extends BaseService
|
||||
* @return mixed
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function runListAds(int $customerId): mixed
|
||||
public function runListAds(int $customerId,$options): mixed
|
||||
{
|
||||
|
||||
// $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.
|
||||
$groupAdsResourceName = self::getAds($googleAdsClient->getGoogleAdsClient(), $customerId);
|
||||
$groupAdsResourceName = self::getAds($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
|
||||
// dump(json_encode($groupAdsResourceName));
|
||||
if (is_array($groupAdsResourceName)) {
|
||||
self::saveAds($groupAdsResourceName);
|
||||
|
@ -33,6 +33,7 @@ use app\util\ArgumentParser;
|
||||
//use Google\Protobuf\Internal\RepeatedField;
|
||||
|
||||
|
||||
use DateTime;
|
||||
use think\facade\Db as ThinkDb;
|
||||
use app\model\Ad as AdModel;
|
||||
use app\model\Asset as AssetModel;
|
||||
@ -76,10 +77,11 @@ class GoogleAdsAssetRelationService extends BaseService
|
||||
*/
|
||||
public function runListAssetRelations(int $customerId): mixed
|
||||
{
|
||||
// dump($customerId);
|
||||
// Creates a single shared budget to be used by the campaigns added below.
|
||||
$assetsResourceName = self::getAssetRelations($customerId);
|
||||
// dump(json_encode($assetsResourceName));
|
||||
if (is_array($assetsResourceName)) {
|
||||
if (is_array($assetsResourceName && count($assetsResourceName) > 0)) {
|
||||
self::saveAssetRelations($assetsResourceName);
|
||||
}
|
||||
// return $assetsResourceName;
|
||||
@ -142,12 +144,18 @@ class GoogleAdsAssetRelationService extends BaseService
|
||||
$month = $dateDetails['month'];
|
||||
$season = $dateDetails['season'];
|
||||
|
||||
// dump($year, $month, $season);
|
||||
|
||||
// 获取所有素材
|
||||
// $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');
|
||||
|
||||
if (!$resourceNames) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// dump($resourceNames);return($resourceNames);
|
||||
$result = [];
|
||||
foreach ($resourceNames as $resourceName) {
|
||||
@ -240,17 +248,17 @@ class GoogleAdsAssetRelationService extends BaseService
|
||||
|
||||
// 提取年和月
|
||||
$year = (int)$dateObj->format('Y');
|
||||
$month = (int)$dateObj->format('m');
|
||||
$month = (int)$dateObj->format('Ym');
|
||||
|
||||
// 计算季度
|
||||
if ($month >= 1 && $month <= 3) {
|
||||
$season = (int)$dateObj->format('Ym') . '01'; // Q1
|
||||
$season = (int)$dateObj->format('Y') . '01'; // Q1
|
||||
} elseif ($month >= 4 && $month <= 6) {
|
||||
$season = (int)$dateObj->format('Ym') . '02'; // Q2
|
||||
$season = (int)$dateObj->format('Y') . '02'; // Q2
|
||||
} elseif ($month >= 7 && $month <= 9) {
|
||||
$season = (int)$dateObj->format('Ym') . '03'; // Q3
|
||||
$season = (int)$dateObj->format('Y') . '03'; // Q3
|
||||
} else {
|
||||
$season = (int)$dateObj->format('Ym') . '04'; // Q4
|
||||
$season = (int)$dateObj->format('Y') . '04'; // Q4
|
||||
}
|
||||
|
||||
return [
|
||||
@ -259,476 +267,4 @@ class GoogleAdsAssetRelationService extends BaseService
|
||||
'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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -70,12 +70,12 @@ class GoogleAdsAssetService extends BaseService
|
||||
* @return mixed
|
||||
* @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.
|
||||
$assetsResourceName = self::getAssets($googleAdsClient->getGoogleAdsClient(), $customerId);
|
||||
$assetsResourceName = self::getAssets($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
|
||||
// dump(json_encode($assetsResourceName));
|
||||
if (is_array($assetsResourceName)) {
|
||||
self::saveAssets($assetsResourceName);
|
||||
|
@ -40,7 +40,7 @@ class GoogleAdsCampaignService extends BaseService
|
||||
private $customerId;
|
||||
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
|
||||
// $googleAdsClient = new GoogleAdsClientService($customerId);
|
||||
@ -75,7 +75,7 @@ class GoogleAdsCampaignService extends BaseService
|
||||
*/
|
||||
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.
|
||||
$budgetResourceName = self::addCampaignBudget($googleAdsClient->getGoogleAdsClient(), $customerId, $options);
|
||||
@ -199,13 +199,11 @@ class GoogleAdsCampaignService extends BaseService
|
||||
* @return mixed
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function runListCampaigns(int $customerId): mixed
|
||||
public function runListCampaigns(int $customerId, $options): mixed
|
||||
{
|
||||
|
||||
// $googleAdsClient = $this->googleAdsClient;
|
||||
$googleAdsClient = new GoogleAdsClientService($customerId);
|
||||
// Creates a single shared budget to be used by the campaigns added below.
|
||||
$campaignsResourceName = self::getCampaigns($googleAdsClient->getGoogleAdsClient(), $customerId);
|
||||
$googleAdsClient = new GoogleAdsClientService($options['refresh_token'], $options['login_customer_id']);
|
||||
$campaignsResourceName = self::getCampaigns($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
|
||||
// dump(json_encode($campaignsResourceName));
|
||||
if (is_array($campaignsResourceName)) {
|
||||
self::saveCampaigns($campaignsResourceName);
|
||||
@ -344,7 +342,6 @@ class GoogleAdsCampaignService extends BaseService
|
||||
$resourceName['year'] = $year;
|
||||
|
||||
|
||||
|
||||
// $resourceName['budget_id'] = $googleAdsRow->getCampaignBudget()->getId();
|
||||
$resourceNames[] = $resourceName;
|
||||
}
|
||||
@ -363,18 +360,18 @@ class GoogleAdsCampaignService extends BaseService
|
||||
$dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象
|
||||
|
||||
// 提取年和月
|
||||
$year = (int) $dateObj->format('Y');
|
||||
$month = (int) $dateObj->format('m');
|
||||
$year = (int)$dateObj->format('Y');
|
||||
$month = (int)$dateObj->format('m');
|
||||
|
||||
// 计算季度
|
||||
if ($month >= 1 && $month <= 3) {
|
||||
$season = (int) $dateObj->format('Ym') . '01'; // Q1
|
||||
$season = (int)$dateObj->format('Ym') . '01'; // Q1
|
||||
} elseif ($month >= 4 && $month <= 6) {
|
||||
$season = (int) $dateObj->format('Ym') . '02'; // Q2
|
||||
$season = (int)$dateObj->format('Ym') . '02'; // Q2
|
||||
} elseif ($month >= 7 && $month <= 9) {
|
||||
$season = (int) $dateObj->format('Ym') . '03'; // Q3
|
||||
$season = (int)$dateObj->format('Ym') . '03'; // Q3
|
||||
} else {
|
||||
$season = (int) $dateObj->format('Ym') . '04'; // Q4
|
||||
$season = (int)$dateObj->format('Ym') . '04'; // Q4
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -5,25 +5,27 @@ namespace app\service;
|
||||
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClientBuilder;
|
||||
use Google\Ads\GoogleAds\Lib\V18\GoogleAdsException;
|
||||
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
|
||||
|
||||
// GoogleAdsClientService.php
|
||||
class GoogleAdsClientService extends BaseService
|
||||
{
|
||||
private $googleAdsClient;
|
||||
private $googleAdsClientWithloginCustomerId;
|
||||
|
||||
public function __construct($customerId = null)
|
||||
public function __construct($refreshToken = null, $loginCustomerId = null)
|
||||
{
|
||||
// 如果没有传入 customerId,则从环境变量中获取
|
||||
if ($customerId) {
|
||||
$this->customerId = $customerId;
|
||||
} else {
|
||||
$this->customerId = getenv('GOOGLE_ADS_CUSTOMER_ID');
|
||||
}
|
||||
// if ($customerId) {
|
||||
// $this->customerId = $customerId;
|
||||
// } else {
|
||||
// $this->customerId = getenv('GOOGLE_ADS_CUSTOMER_ID');
|
||||
// }
|
||||
|
||||
// 从数据库获取 refreshToken
|
||||
$refreshToken = $this->getRefreshTokenFromDatabase($this->customerId);
|
||||
// $refreshToken = $this->getRefreshTokenFromDatabase($this->customerId);
|
||||
|
||||
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
|
||||
@ -33,10 +35,19 @@ class GoogleAdsClientService extends BaseService
|
||||
->build();
|
||||
|
||||
// 初始化 Google Ads Client
|
||||
if ($loginCustomerId) {
|
||||
$this->googleAdsClientWithloginCustomerId = (new GoogleAdsClientBuilder())
|
||||
->fromFile()
|
||||
->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;
|
||||
}
|
||||
|
||||
public function getGoogleAdsClientWithloginCustomerId()
|
||||
{
|
||||
return $this->googleAdsClientWithloginCustomerId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,13 +58,14 @@ class GoogleAdsGroupService extends BaseService
|
||||
* @return mixed
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function runListGroups(int $customerId): mixed
|
||||
public function runListGroups(int $customerId, $options): mixed
|
||||
{
|
||||
|
||||
// $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.
|
||||
$groupsResourceName = self::getGroups($googleAdsClient->getGoogleAdsClient(), $customerId);
|
||||
$groupsResourceName = self::getGroups($googleAdsClient->getGoogleAdsClientWithloginCustomerId(), $customerId);
|
||||
// dump(json_encode($groupsResourceName));
|
||||
if (is_array($groupsResourceName)) {
|
||||
self::saveGroups($groupsResourceName);
|
||||
@ -169,7 +170,7 @@ class GoogleAdsGroupService extends BaseService
|
||||
public function runAddGroup($options): mixed
|
||||
{
|
||||
// $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.
|
||||
$resourceNames = self::addGroup($googleAdsClient->getGoogleAdsClient(), $options['customer_id'], $options['campaign_id']);
|
||||
|
||||
|
@ -5,10 +5,11 @@ namespace app\service;
|
||||
use GuzzleHttp\Client;
|
||||
use think\facade\Db as ThinkDb;
|
||||
use app\model\ThirdUserAdvertiser;
|
||||
use app\model\ThirdUser;
|
||||
|
||||
class GoogleOAuthService
|
||||
{
|
||||
public function getAuthUrl()
|
||||
public function getAuthUrl($state = '')
|
||||
{
|
||||
$clientId = getenv('GOOGLE_CLIENT_ID');
|
||||
$redirectUri = getenv('GOOGLE_REDIRECT_URI');
|
||||
@ -17,17 +18,30 @@ class GoogleOAuthService
|
||||
$accessType = 'offline';
|
||||
|
||||
// $state = 'state_parameter_passthrough_value'; // 可选,保护防止CSRF
|
||||
// 生成随机的state参数,防止CSRF攻击
|
||||
// $state = bin2hex(random_bytes(16)); // 生成一个随机字符串
|
||||
|
||||
// 将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";
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -45,7 +59,94 @@ class GoogleOAuthService
|
||||
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表
|
||||
// $thirdUser = new \App\Models\ThirdUser();
|
||||
@ -62,28 +163,35 @@ class GoogleOAuthService
|
||||
];
|
||||
$tableName = 'bps_third_user';
|
||||
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'bps' . $tableName;
|
||||
if (!empty($state)) {
|
||||
|
||||
$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}
|
||||
(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);
|
||||
}
|
||||
|
||||
@ -103,7 +211,7 @@ class GoogleOAuthService
|
||||
}
|
||||
|
||||
|
||||
public function revokeToken($accessToken)
|
||||
public function revokeToken($accessToken, $third_user_id)
|
||||
{
|
||||
$client = new Client();
|
||||
$client->post('https://oauth2.googleapis.com/revoke', [
|
||||
@ -113,16 +221,19 @@ class GoogleOAuthService
|
||||
]);
|
||||
|
||||
// 在数据库中删除或标记该`access_token(其实是refresh_token)`为无效
|
||||
// ThirdUserModel::where('access_token', $accessToken)->delete();
|
||||
$tableName = "bps.bps_third_user";
|
||||
$sql = "UPDATE {$tableName} SET access_token = '' WHERE access_token = :access_token";
|
||||
ThirdUserAdvertiser::where('doc_', $third_user_id)->delete();
|
||||
|
||||
$tableName = 'bps_third_user';
|
||||
$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 // 这里的 $accessToken 是您想要匹配的值
|
||||
'access_token' => '', // 这里的 $accessToken 是您想要匹配的值
|
||||
'id' => $third_user_id, // 这里的 $accessToken 是您想要匹配的值
|
||||
];
|
||||
|
||||
// 执行 SQL 语句
|
||||
ThinkDb::execute($sql, $data);
|
||||
$result = ThinkDb::execute($sql, $data);
|
||||
// ThirdUser::where('access_token', $accessToken)->delete();
|
||||
|
||||
}
|
||||
|
||||
public function useRefreshToken($refreshToken)
|
||||
@ -152,7 +263,7 @@ class GoogleOAuthService
|
||||
$customers = ThirdUserAdvertiser::alias('tua')
|
||||
->join('bps.bps_third_user tu', 'tua.doc_ = tu.id') // 连接 bps_third_user 表
|
||||
->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(); // 执行查询
|
||||
|
||||
// 如果没有找到符合条件的广告主,抛出异常
|
||||
@ -162,7 +273,7 @@ class GoogleOAuthService
|
||||
}
|
||||
|
||||
// 转换为简单的数组(提取 advertiser_id)
|
||||
return $customers->column('advertiser_id');
|
||||
return $customers->toArray();
|
||||
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ use app\event\GoogleAdsGroups;
|
||||
use app\event\GoogleAdsAds;
|
||||
use app\event\GoogleAdsAssets;
|
||||
use app\event\GoogleAdsAssetRelations;
|
||||
use app\event\GoogleAdsCustomers;
|
||||
use app\event\GoogleAdsDateDatas;
|
||||
|
||||
|
||||
@ -40,6 +41,9 @@ return [
|
||||
GoogleAdsAssetRelations::VIDEOASSET => [
|
||||
[GoogleAdsAssetRelations::class, 'getVideoAssetRelations'],
|
||||
],
|
||||
GoogleAdsCustomers::CUSTOMERADD => [
|
||||
[GoogleAdsCustomers::class, 'addCustomers'],
|
||||
],
|
||||
|
||||
|
||||
];
|
||||
|
@ -21,7 +21,7 @@ global $argv;
|
||||
return [
|
||||
'webman' => [
|
||||
'handler' => Http::class,
|
||||
'listen' => 'http://0.0.0.0:8042',
|
||||
'listen' => 'http://0.0.0.0:8045',
|
||||
'count' => cpu_count() * 4,
|
||||
'user' => '',
|
||||
'group' => '',
|
||||
|
@ -15,6 +15,7 @@
|
||||
//use app\controller\IndexController;
|
||||
use app\controller\AdController;
|
||||
use app\controller\OAuthController;
|
||||
use app\controller\CustomerController;
|
||||
use app\controller\GoogleAdsController;
|
||||
use support\Request;
|
||||
use Webman\Route;
|
||||
@ -68,17 +69,25 @@ Route::group('/googleads', function () {
|
||||
})->middleware([
|
||||
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::get('/code', [OAuthController::class, 'getAuthCode']);
|
||||
Route::post('/callback', [OAuthController::class, 'handleCallback']);
|
||||
Route::post('/refresh_token_get', [OAuthController::class, 'getRefreshToken']);
|
||||
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,
|
||||
]);
|
||||
Route::post('/refresh_token_revoke', [OAuthController::class, 'revokeRefreshToken']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -128,9 +137,7 @@ Route::group('/googleads', function () {
|
||||
Route::group('/account_link', function () {
|
||||
Route::post('/create', [GoogleAdsController::class, 'createLinkManagerToClient']);
|
||||
});
|
||||
Route::group('/account_link', function () {
|
||||
Route::post('/list', [GoogleAdsController::class, 'accessibleCustomers']);
|
||||
});
|
||||
|
||||
Route::group('/datedata', function () {
|
||||
Route::post('/list', [GoogleAdsController::class, 'listDateDatas']);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user