Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConvertObjectToXml does not convert $campaign->biddingStrategyConfiguration #191

Closed
jclee100 opened this issue Dec 8, 2016 · 6 comments
Closed
Assignees

Comments

@jclee100
Copy link
Contributor

jclee100 commented Dec 8, 2016

Hi,

I am using BatchJobUtils->UploadBatchJobOperations() to batch create my campaign (with other entities).

Api version v201609, googleads-php-lib 13.1.0

I am getting this in response to my campaign operation:

array (
  0 => 
  RequiredError::__set_state(array(
     'reason' => 'REQUIRED',
     'fieldPath' => 'operations[1].operand.biddingStrategyConfiguration',
     'trigger' => '',
     'errorString' => 'RequiredError.REQUIRED',
     'ApiErrorType' => 'RequiredError',
     '_parameterMap' => 
    array (
      'ApiError.Type' => 'ApiErrorType',
    ),
  )),
)  
...

In my campaign operation, the operand does have biddingStrategyConfiguration (I am using scheme in place of type). However, I noticed the xml output from XmlSerializer->ConvertObjectToXml() does not.

Also note that when I use CampaignService to ADD my campaign, it goes through with no problem.

Here's a dump of the campaign operation and its corresponding XML output taken from
googleads/googleads-php-lib/src/Google/Api/Ads/AdWords/Util/XmlSerializer->ConvertObjectToXml():

...
1 => CampaignOperation {#331 ▼
      +operand: Campaign {#328 ▼
        +id: -100000002
        +name: "Campaign 2"
        +status: "ENABLED"
        +servingStatus: null
        +startDate: null
        +endDate: null
        +budget: Budget {#332 ▶}
        +conversionOptimizerEligibility: null
        +adServingOptimizationStatus: null
        +frequencyCap: null
        +settings: null
        +advertisingChannelType: "SEARCH"
        +advertisingChannelSubType: null
        +networkSetting: null
        +labels: null
        +biddingStrategyConfiguration: BiddingStrategyConfiguration {#325 ▼
          +biddingStrategyId: null
          +biddingStrategyName: null
          +biddingStrategyType: null
          +biddingStrategySource: null
          +biddingScheme: ManualCpcBiddingScheme {#323 ▶}
          +bids: null
        }
        +campaignTrialType: null
        +baseCampaignId: null
        +forwardCompatibilityMap: null
        +trackingUrlTemplate: null
        +urlCustomParameters: null
        +vanityPharma: null
        +selectiveOptimization: null
      }
      +operator: "ADD"
      +OperationType: null
      -_parameterMap: array:1 [▼
        "Operation.Type" => "OperationType"
      ]
    }
...
...
<operations
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:CampaignOperation">
        <operand xsi:type="ns1:Campaign">
            <id>-100000002</id>
            <name>Campaign 2</name>
            <status>ENABLED</status>
            <budget xsi:type="ns1:Budget">
                <budgetId>-1</budgetId>
            </budget>
            <advertisingChannelType>SEARCH</advertisingChannelType>
        </operand>
        <operator>ADD</operator>
    </operations>
...
@fiboknacky
Copy link
Member

Hi @komirad

Could you please share your code snippet that generates the XML sent to BatchJobService?
In addition, could you please tell me your corresponding batch job ID too?

Thanks in advance!

Cheers,
Knack

@fiboknacky fiboknacky self-assigned this Dec 8, 2016
@jclee100
Copy link
Contributor Author

jclee100 commented Dec 8, 2016

Hi @fiboknacky

Batch job id should be: 416060804 (There are more if you need them)

The snippet (with the added dump() functions) used to generate the above:

public function ConvertObjectToXml($object, $rootElementName, $useXsiType) {
      dump($object);
    $document = new DOMDocument('1.0', 'UTF-8');
    $document->appendChild(
        self::ConvertObjectToElement($object, $rootElementName, $document,
            $useXsiType));
    $xml = XmlUtils::GetXmlFromDom($document);

    if ($useXsiType) {
      // Insert links to definitions of the ns1 and xsi namespaces.
      $xml = preg_replace('/<ns1:mutate/',
          '<ns1:mutate ' . self::ADWORDS_NS_ATTR_PREFIX
              . $object::WSDL_NAMESPACE . '"', $xml);
      $xml = preg_replace('/<operations/',
          '<operations ' . self::XSI_ATTRIBUTE, $xml);
    }
    dump($xml);
    return $xml;
  }

Found in: https://github.com/googleads/googleads-php-lib/blob/master/src/Google/Api/Ads/AdWords/Util/XmlSerializer.php#L51-L67

This is traced back to my code:

$this->batchJobUtils = new \BatchJobUtils($this->batchJob->uploadUrl->url);
$this->batchJobUtils->UploadBatchJobOperations($operations);

From: https://github.com/googleads/googleads-php-lib/blob/master/src/Google/Api/Ads/AdWords/Util/v201609/BatchJobUtils.php#L85-L89

Full XML output: http://pastebin.com/jm8Y9aj2 (notice the BiddingStrategyConfiguration are there for AdGroupOperations)

Let me know if you need me to serialize the $operations param for you.

@fiboknacky
Copy link
Member

Hello @komirad

Thanks for the batch job ID.
Sorry if it's not clear. I meant the code snippet that you used to create operations.
In other words, the snippet that you put data into your $operations in the above reply.

Could you please provide that too?
Thanks in advance.

Best,
Knack

@jclee100
Copy link
Contributor Author

jclee100 commented Dec 8, 2016

Hi @fiboknacky

It's in OOP so it's broken up into many files but I'll extract the methods and relevant parts here.

$operations = [];
...
$campaignOperation = (new MutateCampaign('ADD'))
            ->usingCampaign($adWordsCampaign)
            ->withBudget($budgetMutator->budget)
            ->getOperation(true);
$operations = array_merge($operations, [$campaignOperation]);
...
$batchJobHandler = (new BatchJobHandler($this->adWordsUser))
            ->handle($operations, $adWordsCampaign->store);

Uploading the operation using the library:

class BatchJobHandler {
    ...
    public function handle(Array $operations, Store $store) {
        ...
        $this->batchJobUtils = new \BatchJobUtils($this->batchJob->uploadUrl->url);
        $this->batchJobUtils->UploadBatchJobOperations($operations);
        ...
    }
}

Here I build the operation and take the Campaign object from the model:

class MutateCampaign
{
    ...
    public function getOperation($useTempId = false) {

        if($useTempId) {
            $this->campaign->id = AdWordsTempIdCalculator::Calculate($this->campaignModel);
        }

        $operation = new \CampaignOperation();
        $operation->operand = $this->campaign;
        $operation->operator = $this->operator;
        return $operation;
    }

    public function usingCampaign(AdWordsCampaign $campaignModel){
        $this->campaignModel = $campaignModel;
        $this->campaign = $this->campaignModel->toAdWordsClass();
        return $this;
    }
}

Here I create the Campaign object from my model:

class AdWordsCampaign
{
    ...
    public function toAdWordsClass(): \Campaign {
        // Builds a AdWords Campaign from this model's attributes
        $campaign = new \Campaign();
        $campaign->id = $this->fieldsHelper()->id;
        $campaign->name = $this->fieldsHelper()->name;
        $campaign->status = $this->fieldsHelper()->status;
        $campaign->budget = $this->fieldsHelper()->getAsObject('budget');
        if($this->fieldsHelper()->advertisingChannelType) {
            $campaign->advertisingChannelType = $this->fieldsHelper()->advertisingChannelType;
        }
        if($this->fieldsHelper()->advertisingChannelSubType) {
            $campaign->advertisingChannelSubType = $this->fieldsHelper()->advertisingChannelSubType;
        }

        $campaign->biddingStrategyConfiguration = $this->fieldsHelper()->getAsObject('biddingStrategyConfiguration');

        return $campaign;
    }
}

Here's the relevant portion that is used to convert the array stored in the model to biddingStrategyConfiguration attribute:

$biddingStrategyConfiguration = new \BiddingStrategyConfiguration();
                $biddingStrategyConfiguration->biddingStrategyType = $this->biddingStrategyConfiguration['biddingStrategyType'] ?? null;
                if(isset($this->biddingStrategyConfiguration['biddingScheme'])) {
                    $biddingSchemeType = '\\'.$this->biddingStrategyConfiguration['biddingScheme']['Type'];
                    $biddingStrategyConfiguration->biddingScheme = new $biddingSchemeType;
                    foreach($this->biddingStrategyConfiguration['biddingScheme'] as $key => $value) {
                        if($key !== 'Type') $biddingStrategyConfiguration->biddingScheme->$key = $value;
                    }
                }

Not sure how helpful the above is.

From the dump of the $operations variable, everything looks to be working correctly except that the biddingStrategyConfiguration is not showing when converting to XML. Hopefully, it's not me making a stupid mistake somewhere haha.

@fiboknacky
Copy link
Member

Hello @komirad

I could reproduce this issue as you reported. Thanks for this.
I'm working to see how we can fix this.
As a workaround for this case, please set the biddingStrategyType alongside with biddingScheme.

As for your information, our new BatchJobs in the experimental branch isn't affected by this issue in case you wish to try. :-)

Best,
Knack

@fiboknacky
Copy link
Member

FYI, this issues was fixed with v16.1.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants