275 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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 DateTime;
 | ||
| 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, $date): array
 | ||
|     {
 | ||
| //        dump($customerId);
 | ||
|         // Creates a single shared budget to be used by the campaigns added below.
 | ||
|         $assetsResourceName = self::getAssetRelations($customerId,$date);
 | ||
| 
 | ||
|         if (is_array($assetsResourceName) && count($assetsResourceName) > 0) {
 | ||
| //              dump($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) && count($assetsResourceName) > 0) {
 | ||
|             self::saveAssetRelations($assetsResourceName);
 | ||
|         }
 | ||
| //        return $assetsResourceName;
 | ||
|         return 'insert success';
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     /**
 | ||
|      *  在数据库中保存广告素材信息
 | ||
|      * @param $assetsResourceName
 | ||
|      * @return void
 | ||
|      */
 | ||
|     public static function saveAssetRelations($assetsResourceName)
 | ||
|     {
 | ||
| //        dump($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,month,season,year, create_at, update_at)
 | ||
|                 VALUES (:asset_id, :ad_id, :ad_group_id, :campaign_id, :date,:month,:season,:year, 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, $date = '2024-12-19')
 | ||
|     {
 | ||
|         // 调用私有方法提取 year, month, season
 | ||
|         $dateDetails = self::extractDateDetails($date);
 | ||
| 
 | ||
|         $year   = $dateDetails['year'];
 | ||
|         $month  = $dateDetails['month'];
 | ||
|         $season = $dateDetails['season'];
 | ||
| 
 | ||
| //        dump($year, $month, $season);
 | ||
| 
 | ||
|         // 获取所有素材
 | ||
| //        $assets = AssetModel::where('asset_type', 4)->select(); //图片素材
 | ||
| 
 | ||
|         $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) {
 | ||
|             // 获取广告表中的所有广告
 | ||
|             $ads = ThinkDb::table('bps.bps_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_set_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;
 | ||
|                 $result[$resourceName['asset_id']]['month']       = $month;
 | ||
|                 $result[$resourceName['asset_id']]['season']      = $season;
 | ||
|                 $result[$resourceName['asset_id']]['year']        = $year;
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| //        dump($result);
 | ||
|         return $result;
 | ||
| //        dump('Google Ads Asset synchronization completed.');
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      *
 | ||
|      * @param int $customerId the customer ID
 | ||
|      */
 | ||
| 
 | ||
|     public static function getVideoAssetRelations(int $customerId)
 | ||
|     {
 | ||
| //        $date = date('Y-m-d');
 | ||
|         $date = '2025-02-07';
 | ||
|         // 调用私有方法提取 year, month, season
 | ||
|         $dateDetails = self::extractDateDetails($date);
 | ||
| 
 | ||
|         $year   = $dateDetails['year'];
 | ||
|         $month  = $dateDetails['month'];
 | ||
|         $season = $dateDetails['season'];
 | ||
| 
 | ||
|         // 获取所有素材
 | ||
| //        $assets = AssetModel::where('asset_type', 2)->select(); //视频素材
 | ||
| 
 | ||
|         $resourceNames = AssetModel::where('asset_type', 2)->where('customer_id', $customerId)
 | ||
|             ->column('asset_id, resource_name');
 | ||
|         if (!$resourceNames) {
 | ||
|             return [];
 | ||
|         }
 | ||
| //          dump($resourceNames);return($resourceNames);
 | ||
|         $result = [];
 | ||
|         foreach ($resourceNames as $resourceName) {
 | ||
|             // 获取广告表中的所有匹配的广告
 | ||
|             $ads = ThinkDb::table('bps.bps_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_set_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;
 | ||
|                 $result[$resourceName['asset_id']]['month']       = $month;
 | ||
|                 $result[$resourceName['asset_id']]['season']      = $season;
 | ||
|                 $result[$resourceName['asset_id']]['year']        = $year;
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
|         return $result;
 | ||
| //        dump('Google Ads Asset synchronization completed.');
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     /**
 | ||
|      * 从日期字符串中提取年、月、季节信息,并返回这些信息
 | ||
|      *
 | ||
|      * @param string $date 日期,格式为 'Y-m-d'
 | ||
|      * @return array 包含 year, month 和 season 的数组
 | ||
|      */
 | ||
|     private static function extractDateDetails($date)
 | ||
|     {
 | ||
|         $dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象
 | ||
| 
 | ||
|         // 提取年和月
 | ||
|         $year  = (int)$dateObj->format('Y');
 | ||
|         $month = (int)$dateObj->format('m');
 | ||
| 
 | ||
|         // 计算季度
 | ||
|         if ($month >= 1 && $month <= 3) {
 | ||
|             $season = (int)$dateObj->format('Y') . '01'; // Q1
 | ||
|         } elseif ($month >= 4 && $month <= 6) {
 | ||
|             $season = (int)$dateObj->format('Y') . '02'; // Q2
 | ||
|         } elseif ($month >= 7 && $month <= 9) {
 | ||
|             $season = (int)$dateObj->format('Y') . '03'; // Q3
 | ||
|         } else {
 | ||
|             $season = (int)$dateObj->format('Y') . '04'; // Q4
 | ||
|         }
 | ||
|         $month = (int)$dateObj->format('Ym');
 | ||
|         return [
 | ||
|             'year' => $year,
 | ||
|             'month' => $month,
 | ||
|             'season' => $season
 | ||
|         ];
 | ||
|     }
 | ||
| }
 | 
