谷歌创意素材2
This commit is contained in:
		
							parent
							
								
									f145391b52
								
							
						
					
					
						commit
						f385f6f2ef
					
				| @ -10,6 +10,7 @@ use app\service\GoogleAdsCampaignService; | |||||||
| use app\service\GoogleAdsGroupService; | use app\service\GoogleAdsGroupService; | ||||||
| use app\service\GoogleAdsAdService; | use app\service\GoogleAdsAdService; | ||||||
| use app\service\GoogleAdsAssetService; | use app\service\GoogleAdsAssetService; | ||||||
|  | use app\service\GoogleAdsAssetRelationService; | ||||||
| use app\service\GoogleAdsAccountService; | use app\service\GoogleAdsAccountService; | ||||||
| use support\Response; | use support\Response; | ||||||
| use DI\Annotation\Inject; | use DI\Annotation\Inject; | ||||||
| @ -42,6 +43,12 @@ class GoogleAdsController | |||||||
|      */ |      */ | ||||||
|     private $googleAdsAssetService; |     private $googleAdsAssetService; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @Inject | ||||||
|  |      * @var GoogleAdsAssetRelationService | ||||||
|  |      */ | ||||||
|  |     private $googleAdsAssetRelationService; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @Inject |      * @Inject | ||||||
|      * @var GoogleAdsAccountService |      * @var GoogleAdsAccountService | ||||||
| @ -93,6 +100,17 @@ class GoogleAdsController | |||||||
|         // 继续处理 Google Ads API 操作
 |         // 继续处理 Google Ads API 操作
 | ||||||
|         return $this->getAssets($options); |         return $this->getAssets($options); | ||||||
|     } |     } | ||||||
|  |     public function listAssetRelations(Request $request) | ||||||
|  |     { | ||||||
|  |         $options = $request->all(); | ||||||
|  | 
 | ||||||
|  |         // 继续处理 Google Ads API 操作
 | ||||||
|  |         if($options['asset_type'] == 2){ | ||||||
|  |             return $this->getVideoAssetRelations($options); | ||||||
|  |         }elseif($options['asset_type'] == 4){ | ||||||
|  |             $this->getAssetRelations($options); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     public function listDateDatas(Request $request) |     public function listDateDatas(Request $request) | ||||||
|     { |     { | ||||||
| @ -279,6 +297,27 @@ class GoogleAdsController | |||||||
| //        return $this->successResponse(['assets_list' => $resourceName]);
 | //        return $this->successResponse(['assets_list' => $resourceName]);
 | ||||||
|         return $this->successResponse(['assets_list' => 'succeed added']); |         return $this->successResponse(['assets_list' => 'succeed added']); | ||||||
|     } |     } | ||||||
|  |     /** | ||||||
|  |      * get assets | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function getAssetRelations($options): Response | ||||||
|  |     { | ||||||
|  |         $resourceName = $this->googleAdsAssetRelationService->runListAssetRelations($options['customer_id']); | ||||||
|  |         return $this->successResponse(['assets_relation_list' => $resourceName]); | ||||||
|  | //        return $this->successResponse(['assets_relation_list' => 'succeed added']);
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * get assets | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function getVideoAssetRelations($options): Response | ||||||
|  |     { | ||||||
|  |         $resourceName = $this->googleAdsAssetRelationService->runListVideoAssetRelations($options['customer_id']); | ||||||
|  |         return $this->successResponse(['assets_relation_list' => $resourceName]); | ||||||
|  | //        return $this->successResponse(['assets_relation_list' => 'succeed added']);
 | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * get date datas |      * get date datas | ||||||
|  | |||||||
							
								
								
									
										297
									
								
								app/event/GoogleAdsAssetRelations.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								app/event/GoogleAdsAssetRelations.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,297 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace app\event; | ||||||
|  | 
 | ||||||
|  | use app\service\GoogleAdsAssetRelationService; | ||||||
|  | use app\service\GoogleOAuthService; | ||||||
|  | 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 GoogleAdsAssetRelations | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @Inject | ||||||
|  |      * @var GoogleOAuthService | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     private $googleOAuthService; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     //微博热榜地址
 | ||||||
|  | //    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 IMAGEASSET = 'googleadsassetrelations_image'; | ||||||
|  |     const VIDEOASSET = 'googleadsassetrelations_video'; | ||||||
|  |     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 listAssetRelations(Request $request) | ||||||
|  |     { | ||||||
|  |         $options = $request->all(); | ||||||
|  | 
 | ||||||
|  |         // 继续处理 Google Ads API 操作
 | ||||||
|  |         return $this->getAssetRelations($options); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * get asset relations | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function getAssetRelations($options) | ||||||
|  |     { | ||||||
|  |         $customers = $this->googleOAuthService->getGoogleAdCustomers([]); | ||||||
|  |         foreach ($customers as $customerId) { | ||||||
|  |             $googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId); | ||||||
|  |             $resourceName = $googleAdsAssetRelationService->runListAssetRelations($customerId); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | //        return $this->successResponse(['ads_list' => $resourceName]);
 | ||||||
|  |     } | ||||||
|  |     /** | ||||||
|  |      * get asset relations | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function getVideoAssetRelations($options) | ||||||
|  |     { | ||||||
|  |         $customers = $this->googleOAuthService->getGoogleAdCustomers([]); | ||||||
|  |         foreach ($customers as $customerId) { | ||||||
|  |             $googleAdsAssetRelationService = new GoogleAdsAssetRelationService($customerId); | ||||||
|  |             $resourceName = $googleAdsAssetRelationService->runListVideoAssetRelations($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 | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -25,6 +25,11 @@ class Ad extends Model | |||||||
|         'ad_group_id' => 'int', |         'ad_group_id' => 'int', | ||||||
|         'customer_id' => 'int', |         'customer_id' => 'int', | ||||||
|     ]; |     ]; | ||||||
|  | 
 | ||||||
|  |     // 设置json类型字段
 | ||||||
|  | 	protected $json = ['metadata']; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     // 默认值设置
 |     // 默认值设置
 | ||||||
|     protected $defaults = [ |     protected $defaults = [ | ||||||
|         'status' => 1, // 广告状态默认值为 'ENABLED'
 |         'status' => 1, // 广告状态默认值为 'ENABLED'
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use app\event\GoogleAdsCampaigns; | |||||||
| use app\event\GoogleAdsGroups; | use app\event\GoogleAdsGroups; | ||||||
| use app\event\GoogleAdsAds; | use app\event\GoogleAdsAds; | ||||||
| use app\event\GoogleAdsAssets; | use app\event\GoogleAdsAssets; | ||||||
|  | use app\event\GoogleAdsAssetRelations; | ||||||
| use app\event\GoogleAdsDateDatas; | use app\event\GoogleAdsDateDatas; | ||||||
| use Webman\Event\Event; | use Webman\Event\Event; | ||||||
| use Workerman\Crontab\Crontab; | use Workerman\Crontab\Crontab; | ||||||
| @ -24,33 +25,33 @@ class UpdateGoogleAdsTask | |||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('10 */15 * * * *', function () { |         new Crontab('10 */15 * * * *', function () { | ||||||
| 
 | 
 | ||||||
|             $dayBeforeYesterdayStart = date('Y-m-d', strtotime('-2 day')); | //            $dayBeforeYesterdayStart = date('Y-m-d', strtotime('-2 day'));
 | ||||||
|             dump($dayBeforeYesterdayStart . '更新' . GoogleAdsDateDatas::type . '开始'); | //            dump($dayBeforeYesterdayStart . '更新' . GoogleAdsDateDatas::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsDateDatas::type, ['date' => $dayBeforeYesterdayStart]); | //            Event::emit(GoogleAdsDateDatas::type, ['date' => $dayBeforeYesterdayStart]);
 | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('20 */15 * * * *', function () { |         new Crontab('20 */15 * * * *', function () { | ||||||
|             $yesterdayStart = date('Y-m-d', strtotime('-1 day')); | //            $yesterdayStart = date('Y-m-d', strtotime('-1 day'));
 | ||||||
|             dump($yesterdayStart . '更新' . GoogleAdsDateDatas::type . '开始'); | //            dump($yesterdayStart . '更新' . GoogleAdsDateDatas::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsDateDatas::type, ['date' => $yesterdayStart]); | //            Event::emit(GoogleAdsDateDatas::type, ['date' => $yesterdayStart]);
 | ||||||
|         } |         } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('30 */15 * * * *', function () { |         new Crontab('30 */15 * * * *', function () { | ||||||
|             //获取今天的 0 点的YYYY-MM-DD格式
 |             //获取今天的 0 点的YYYY-MM-DD格式
 | ||||||
|             $todayStart = date('Y-m-d', strtotime('0 day')); | //            $todayStart = date('Y-m-d', strtotime('0 day'));
 | ||||||
|             dump($todayStart . '更新' . GoogleAdsDateDatas::type . '开始'); | //            dump($todayStart . '更新' . GoogleAdsDateDatas::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsDateDatas::type, ['date' => $todayStart]); | //            Event::emit(GoogleAdsDateDatas::type, ['date' => $todayStart]);
 | ||||||
|         } |         } | ||||||
|         ); |         ); | ||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('40 */15 * * * *', function () { |         new Crontab('40 */15 * * * *', function () { | ||||||
|             dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始'); | //            dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsCampaigns::type, []); | //            Event::emit(GoogleAdsCampaigns::type, []);
 | ||||||
|         } |         } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
| @ -63,15 +64,26 @@ class UpdateGoogleAdsTask | |||||||
| 
 | 
 | ||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('55 */15 * * * *', function () { |         new Crontab('55 */15 * * * *', function () { | ||||||
|             dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始'); | //            dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAds::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsAds::type, []); | //            Event::emit(GoogleAdsAds::type, []);
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ); |         ); | ||||||
|         // 每15分钟执行一次
 |         // 每15分钟执行一次
 | ||||||
|         new Crontab('58 */15 * * * *', function () { |         new Crontab('25 */15 * * * *', function () { | ||||||
|             dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始'); | //            dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssets::type . '开始');
 | ||||||
|             Event::emit(GoogleAdsAssets::type, []); | //            Event::emit(GoogleAdsAssets::type, []);
 | ||||||
|  |         } | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         new Crontab('55 */50 * * * *', function () { | ||||||
|  |             dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始'); | ||||||
|  |             Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         new Crontab('55 */51 * * * *', function () { | ||||||
|  |             dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::VIDEOASSET . '开始'); | ||||||
|  |             Event::emit(GoogleAdsAssetRelations::VIDEOASSET, []); | ||||||
|         } |         } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										679
									
								
								app/service/GoogleAdsAssetRelationService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										679
									
								
								app/service/GoogleAdsAssetRelationService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,679 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace app\service; | ||||||
|  | 
 | ||||||
|  | use app\service\GoogleAdsClientService; | ||||||
|  | use app\model\ThirdUserAdvertiser; | ||||||
|  | use app\util\Helper; | ||||||
|  | use app\util\ArgumentNames; | ||||||
|  | use app\util\ArgumentParser; | ||||||
|  | 
 | ||||||
|  | //use Google\Ads\GoogleAds\Lib\V18\GoogleAdsClient;
 | ||||||
|  | //use Google\Ads\GoogleAds\Util\FieldMasks;
 | ||||||
|  | //use Google\Ads\GoogleAds\Util\V18\ResourceNames;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Common\ResponsiveSearchAdInfo;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Enums\AdGroupAdStatusEnum\AdGroupAdStatus;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Enums\GoogleAdsFieldCategoryEnum\GoogleAdsFieldCategory;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Enums\GoogleAdsFieldDataTypeEnum\GoogleAdsFieldDataType;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Errors\GoogleAdsError;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Resources\Ad;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Resources\AdGroupAd;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Resources\GoogleAdsField;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\AdGroupAdOperation;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\AdOperation;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\MutateAdGroupAdsRequest;
 | ||||||
|  | //
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Common\AdTextAsset;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Enums\ServedAssetFieldTypeEnum\ServedAssetFieldType;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\GoogleAdsRow;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\MutateAdsRequest;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsFieldsRequest;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
 | ||||||
|  | //use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsStreamRequest;
 | ||||||
|  | //use Google\Protobuf\Internal\RepeatedField;
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | use think\facade\Db as ThinkDb; | ||||||
|  | use app\model\Ad as AdModel; | ||||||
|  | use app\model\Asset as AssetModel; | ||||||
|  | use app\model\AssetRelation as AssetRelationModel; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | use Google\ApiCore\ApiException; | ||||||
|  | 
 | ||||||
|  | class GoogleAdsAssetRelationService extends BaseService | ||||||
|  | { | ||||||
|  | //    private $googleAdsClient;
 | ||||||
|  |     private $customerId; | ||||||
|  | 
 | ||||||
|  |     public function __construct($customerId = null) | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 从数据库动态获取 google RefreshToken
 | ||||||
|  | //    private function getRefreshTokenFromDatabase($advertiserId)
 | ||||||
|  | //    {
 | ||||||
|  | //        // 通过 advertiser_id 查询 ThirdUserAdvertiser,联表查询 ThirdUser 数据
 | ||||||
|  | //        $userAdvertiser = ThirdUserAdvertiser::with('googleUser')  // 联表查询 user 关联
 | ||||||
|  | //        ->where('advertiser_id', $advertiserId)  // 根据 advertiser_id 查询
 | ||||||
|  | //        ->find();  // 获取第一个结果
 | ||||||
|  | //
 | ||||||
|  | //// 如果找到广告主数据
 | ||||||
|  | //        if ($userAdvertiser && $userAdvertiser->googleUser) {
 | ||||||
|  | //            // 获取关联用户的 access_token
 | ||||||
|  | //            return $userAdvertiser->googleUser ? $userAdvertiser->googleUser->access_token : null;
 | ||||||
|  | //        } else {
 | ||||||
|  | ////            return $this->errorResponse('101', '未找到该广告主或关联的用户');
 | ||||||
|  | //        }
 | ||||||
|  | //    }
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /* @param int $customerId the customer ID | ||||||
|  |      * @param $options | ||||||
|  |      * @return mixed | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function runListAssetRelations(int $customerId): mixed | ||||||
|  |     { | ||||||
|  |         // 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)) { | ||||||
|  |             self::saveAssetRelations($assetsResourceName); | ||||||
|  |         } | ||||||
|  | //        return $assetsResourceName;
 | ||||||
|  |         return 'insert success'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /* @param int $customerId the customer ID | ||||||
|  |      * @param $options | ||||||
|  |      * @return mixed | ||||||
|  |      * @throws ApiException | ||||||
|  |      */ | ||||||
|  |     public function runListVideoAssetRelations(int $customerId): mixed | ||||||
|  |     { | ||||||
|  |         // Creates a single shared budget to be used by the campaigns added below.
 | ||||||
|  |         $assetsResourceName = self::getVideoAssetRelations($customerId); | ||||||
|  | //        dump(json_encode($assetsResourceName));
 | ||||||
|  |         if (is_array($assetsResourceName)) { | ||||||
|  |             self::saveAssetRelations($assetsResourceName); | ||||||
|  |         } | ||||||
|  | //        return $assetsResourceName;
 | ||||||
|  |         return 'insert success'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      *  在数据库中保存广告素材信息 | ||||||
|  |      * @param $assetsResourceName | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public static function saveAssetRelations($assetsResourceName) | ||||||
|  |     { | ||||||
|  |         $tableName = 'bps_google_ads_asset_relations'; | ||||||
|  |         $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName; | ||||||
|  |         foreach ($assetsResourceName as $data) { | ||||||
|  |             // 修改后的插入 SQL 语句
 | ||||||
|  |              $sql = "INSERT INTO {$tableName} | ||||||
|  |                 (asset_id, ad_id, ad_group_id, campaign_id, date, create_at, update_at) | ||||||
|  |                 VALUES (:asset_id, :ad_id, :ad_group_id, :campaign_id, :date, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) | ||||||
|  |                 ON CONFLICT (asset_id, ad_id, date) | ||||||
|  |                 DO NOTHING"; // 如果 (asset_id, ad_id, date) 存在,忽略插入操作
 | ||||||
|  | 
 | ||||||
|  |             ThinkDb::execute($sql, $data); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * | ||||||
|  |      * @param int $customerId the customer ID | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     public static function getAssetRelations(int $customerId) | ||||||
|  |     { | ||||||
|  |         // 获取所有素材
 | ||||||
|  | //        $assets = AssetModel::where('asset_type', 4)->select(); //图片素材
 | ||||||
|  | 
 | ||||||
|  |         $resourceNames = AssetModel::where('asset_type', 4) | ||||||
|  |             ->column('asset_id, resource_name'); | ||||||
|  | 
 | ||||||
|  | //          dump($resourceNames);return($resourceNames);
 | ||||||
|  |         $result = []; | ||||||
|  |         foreach ($resourceNames as $resourceName) { | ||||||
|  |             // 获取广告表中的所有广告
 | ||||||
|  |             $ads = ThinkDb::table('bps.bps_google_ads_ad') | ||||||
|  | //            ->whereRaw("metadata->'marketing_images' @> ?", ['["customers/4060397299/assets/191677352383"]'])
 | ||||||
|  | //            ->whereOrRaw("metadata->'square_marketing_images' @> ?", ['["customers/4060397299/assets/191677352383"]'])
 | ||||||
|  |                 ->whereRaw("metadata->'marketing_images' @> ?", ['["' . $resourceName['resource_name'] . '"]']) | ||||||
|  |                 ->whereOrRaw("metadata->'square_marketing_images' @> ?", ['["' . $resourceName['resource_name'] . '"]']) | ||||||
|  |                 ->select(); | ||||||
|  | 
 | ||||||
|  | //            $ads = AdModel::where(function ($query) use ($resourceName) {
 | ||||||
|  | //                $query->whereJsonContains('metadata->marketing_images', $resourceName)
 | ||||||
|  | //                      ->WhereOrJsonContains('metadata->square_marketing_images', $resourceName);
 | ||||||
|  | //            })->select();
 | ||||||
|  | //            $result[$resourceName['asset_id']] = $ads;
 | ||||||
|  | 
 | ||||||
|  |             foreach ($ads as $ad) { | ||||||
|  |                 $result[$resourceName['asset_id']]['ad_id']       = $ad['ad_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['ad_group_id'] = $ad['ad_group_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['campaign_id'] = $ad['campaign_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['asset_id']    = $resourceName['asset_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['date']    = date('Y-m-d'); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |         return $result; | ||||||
|  | //        dump('Google Ads Asset synchronization completed.');
 | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * | ||||||
|  |      * @param int $customerId the customer ID | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     public static function getVideoAssetRelations(int $customerId) | ||||||
|  |     { | ||||||
|  |         // 获取所有素材
 | ||||||
|  | //        $assets = AssetModel::where('asset_type', 2)->select(); //视频素材
 | ||||||
|  | 
 | ||||||
|  |         $resourceNames = AssetModel::where('asset_type', 2) | ||||||
|  |             ->column('asset_id, resource_name'); | ||||||
|  | 
 | ||||||
|  | //          dump($resourceNames);return($resourceNames);
 | ||||||
|  |         $result = []; | ||||||
|  |         foreach ($resourceNames as $resourceName) { | ||||||
|  |             // 获取广告表中的所有匹配的广告
 | ||||||
|  |             $ads = ThinkDb::table('bps.bps_google_ads_ad') | ||||||
|  |                 ->whereRaw("metadata->'youtube_videos' @> ?", ['["' . $resourceName['resource_name'] . '"]']) | ||||||
|  |                 ->select(); | ||||||
|  |             foreach ($ads as $ad) { | ||||||
|  |                 $result[$resourceName['asset_id']]['ad_id']       = $ad['ad_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['ad_group_id'] = $ad['ad_group_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['campaign_id'] = $ad['campaign_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['asset_id']    = $resourceName['asset_id']; | ||||||
|  |                 $result[$resourceName['asset_id']]['date']    = date('Y-m-d'); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |         return $result; | ||||||
|  | //        dump('Google Ads Asset synchronization completed.');
 | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 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
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -119,8 +119,8 @@ class GoogleAdsAssetService extends BaseService | |||||||
|         foreach ($assetsResourceName as $data) { |         foreach ($assetsResourceName as $data) { | ||||||
|             // 修改后的插入 SQL 语句
 |             // 修改后的插入 SQL 语句
 | ||||||
|             $sql = "INSERT INTO {$tableName} |             $sql = "INSERT INTO {$tableName} | ||||||
|         (asset_id, customer_id, asset_type, asset_name, resource_name, asset_url, status, metadata, create_at, update_at) |         (asset_id, customer_id, asset_type, asset_name, resource_name, asset_url, status, asset_source,metadata, create_at, update_at) | ||||||
|         VALUES (:asset_id, :customer_id, :asset_type, :asset_name, :resource_name, :asset_url, :status, :metadata, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) |         VALUES (:asset_id, :customer_id, :asset_type, :asset_name, :resource_name, :asset_url, :status,:source, :metadata, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) | ||||||
|         ON CONFLICT (asset_id) |         ON CONFLICT (asset_id) | ||||||
|         DO UPDATE SET |         DO UPDATE SET | ||||||
|             customer_id = EXCLUDED.customer_id, |             customer_id = EXCLUDED.customer_id, | ||||||
| @ -129,6 +129,7 @@ class GoogleAdsAssetService extends BaseService | |||||||
|             resource_name = EXCLUDED.resource_name, |             resource_name = EXCLUDED.resource_name, | ||||||
|             asset_url = EXCLUDED.asset_url, |             asset_url = EXCLUDED.asset_url, | ||||||
|             status = EXCLUDED.status, |             status = EXCLUDED.status, | ||||||
|  |             asset_source = EXCLUDED.asset_source, | ||||||
|             metadata = EXCLUDED.metadata, |             metadata = EXCLUDED.metadata, | ||||||
|             update_at = CURRENT_TIMESTAMP"; // update_at 使用 CURRENT_TIMESTAMP 自动更新
 |             update_at = CURRENT_TIMESTAMP"; // update_at 使用 CURRENT_TIMESTAMP 自动更新
 | ||||||
| 
 | 
 | ||||||
| @ -204,6 +205,7 @@ class GoogleAdsAssetService extends BaseService | |||||||
| 
 | 
 | ||||||
|             $resourceName['status']    = 2; //未定义,先占坑
 |             $resourceName['status']    = 2; //未定义,先占坑
 | ||||||
|             $resourceName['resource_name'] = $googleAdsRow->getAsset()->getResourceName(); |             $resourceName['resource_name'] = $googleAdsRow->getAsset()->getResourceName(); | ||||||
|  |             $resourceName['source'] = $googleAdsRow->getAsset()->getSource(); | ||||||
|             $resourceName['customer_id']   = $googleAdsRow->getCustomer()->getId(); |             $resourceName['customer_id']   = $googleAdsRow->getCustomer()->getId(); | ||||||
| 
 | 
 | ||||||
|             $resourceNames[] = $resourceName; |             $resourceNames[] = $resourceName; | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use app\event\GoogleAdsCampaigns; | |||||||
| use app\event\GoogleAdsGroups; | use app\event\GoogleAdsGroups; | ||||||
| use app\event\GoogleAdsAds; | use app\event\GoogleAdsAds; | ||||||
| use app\event\GoogleAdsAssets; | use app\event\GoogleAdsAssets; | ||||||
|  | use app\event\GoogleAdsAssetRelations; | ||||||
| use app\event\GoogleAdsDateDatas; | use app\event\GoogleAdsDateDatas; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -33,6 +34,12 @@ return [ | |||||||
|     GoogleAdsAssets::type => [ |     GoogleAdsAssets::type => [ | ||||||
|         [GoogleAdsAssets::class, 'getAssets'], |         [GoogleAdsAssets::class, 'getAssets'], | ||||||
|     ], |     ], | ||||||
|  |     GoogleAdsAssetRelations::IMAGEASSET => [ | ||||||
|  |         [GoogleAdsAssetRelations::class, 'getAssetRelations'], | ||||||
|  |     ], | ||||||
|  |     GoogleAdsAssetRelations::VIDEOASSET => [ | ||||||
|  |         [GoogleAdsAssetRelations::class, 'getVideoAssetRelations'], | ||||||
|  |     ], | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ]; | ]; | ||||||
|  | |||||||
| @ -103,6 +103,9 @@ Route::group('/googleads', function () { | |||||||
|     Route::group('/asset', function () { |     Route::group('/asset', function () { | ||||||
|         Route::post('/list', [GoogleAdsController::class, 'listAssets']); |         Route::post('/list', [GoogleAdsController::class, 'listAssets']); | ||||||
|     }); |     }); | ||||||
|  |     Route::group('/asset_relation', function () { | ||||||
|  |         Route::post('/list', [GoogleAdsController::class, 'listAssetRelations']); | ||||||
|  |     }); | ||||||
|     Route::group('/ad', function () { |     Route::group('/ad', function () { | ||||||
|         Route::post('/update', [GoogleAdsController::class, 'updateAd']); |         Route::post('/update', [GoogleAdsController::class, 'updateAd']); | ||||||
|         Route::post('/list', [GoogleAdsController::class, 'listAds']); |         Route::post('/list', [GoogleAdsController::class, 'listAds']); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user