AWS PHP SDK issue with Dynamodb WriteRequestBatch - php

I am experimenting with WriteRequestBatch from AWS SDK for Dynamodb. Below is my code. Everything works except the WriteRequestBatch part. I have no clue why, and was wondering if the community could help me out here. What might I be doing wrong? I have tried googling and searching here and found only 8 other questions that could be related but unfortunately were of no help.
This is where I started from.
$ddb_client = DynamoDbClient::factory(array(
'region' => 'us-east-1',
'key' => 'my_key',
'secret' => 'my_secret'
));
$ddb_client->createTable(array(
'TableName' => 'my_table',
'AttributeDefinitions' => array(
array(
'AttributeName' => 'id',
'AttributeType' => 'S'
),
array(
'AttributeName' => 'ns',
'AttributeType' => 'S'
)
),
'KeySchema' => array(
array(
'AttributeName' => 'id',
'KeyType' => 'HASH'
),
array(
'AttributeName' => 'ns',
'KeyType' => 'RANGE'
)
),
'ProvisionedThroughput' => array(
'ReadCapacityUnits' => 10,
'WriteCapacityUnits' => 10
)
));
$response = $ddb_client->putItem(array(
"TableName" => "my_table",
"Item" => array(
"id" => array("S" => "exp_id"),
"ns" => array("S" => "exp_ns"),
"version" => array("N" => "0"),
),
));
$item = $response['Item'];
$item['version']['N'] = '1';
$put_batch = WriteRequestBatch::factory($ddb_client);
$put_request = new PutRequest(
array(
"Item" => $item,
"Expected" => array(
"version" => array(
"ComparisonOperator" => "EQ",
"AttributeValueList" => array(
array("N" => "0")
)
),
),
),
"my_table"
);
$putBatch->add($put_request);
$putBatch->flush();
This works instead of WriteRequestBatch. I will just have to manage batches to put myself than use WriteRequestBatch doing it for me:
$response = $ddb_client->batchWriteItem(array(
"RequestItems" => array(
"my_table" => array(
array(
"PutRequest" => array(
"Item" => $item,
"Expected" => array(
"version" => array(
"ComparisonOperator" => "EQ",
"AttributeValueList" => array(
array("S" => "0")
)
),
),
)
)
)
)
));

The answer by Geek Stocks is incomplete, but still helpful. One thing you can do handle the asynchronous aspects of the CreateTable operation is to use a Waiter:
$ddb_client->createTable(array('TableName' => 'my_table', ... ));
$ddb_client->waitUntil('TableExists', array('TableName' => 'my_table'));
However, there is also a problem with how you are using the WriteRequestBatch class. When you create a PutRequest, you must pass in the item, not a whole set of PutItem parameters. The WriteRequestBatch is an abstraction over DynamoDB's BatchWriteItem operation, which does not allow things like the Expected parameter. If you want to do that, then you need to use individual PutItem/UpdateItem/DeleteItem requests.
Here is a modified version of your usage of WriteRequestBatch that is correct:
$putBatch = WriteRequestBatch::factory($ddb_client);
$putBatch->add(new PutRequest($item, 'my_table'));
// ADD MORE...
// ...
// ...
$putBatch->flush();
Here is another example of using the WriteRequestBatch from the SDK's User Guide.
EDIT: One more complete example that works that I just tested, that shows the difference between versions prior to 2.7.0 and afterwards
use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Model\BatchRequest\WriteRequestBatch;
use Aws\DynamoDb\Model\BatchRequest\PutRequest;
use Aws\DynamoDb\Model\Item;
$client = DynamoDbClient::factory([/* ... */]);
$batch = WriteRequestBatch::factory($client);
for ($i = 1; $i <= 55; $i++) {
// FOR ANY SDK VERSION
// (NOTE: Does not support new M, L, BOOL, and NULL types)
$item = Item::fromArray(['id' => $i, 'data' => "foo{$i}"]);
// FOR SDK >= 2.7
$item = ['id' => ['N' => $i], 'data' => ['S' => "foo{$i}"]];
$batch->add(new PutRequest($item, 'my-table'));
}
$batch->flush();

Because you currently do not have any "try / catch" error handling around your code you are likely not getting good information on your error.
I placed try/catch blocks on your code and found that the table creates just fine but that the call to putItem fails for the following reason: Requested resource not found
When you create a table it is NOT immediately available. You have to pause until it becomes available. This paragraph of the AWS docs explains this nicely:
CreateTable is an asynchronous operation. Upon receiving a CreateTable request, DynamoDB immediately returns a response with a TableStatus of CREATING . After the table is created, DynamoDB sets the TableStatus to ACTIVE . You can perform read and write operations only on an ACTIVE table. You can use the DescribeTable API to check the table status.
Once you add the call to DescribeTable like it shows, you should be good.

Related

Problem while adding Journal Entry with customer in Quickbook - Message: Passed array has no key for 'Value' when contructing an ReferenceType

I go through this documentation "https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/journalentry"
And tried to add journal entry with line having customer as shown in the below code:
$journal_entry_create['TxnDate'] = date('Y-m-d');
$journal_entry_line = array(
'Amount' => $amount,
'DetailType' => 'JournalEntryLineDetail',
'JournalEntryLineDetail' => array(
'PostingType' => Credit,
'Entity' => array(
'Type' => 'Customer',
'EntityRef' => array(
'type' => 'Customer',
'value' => "2",
'name' => 'Abc'
)
),
'AccountRef' => array(
'name' => 'Account Name',
'value' => '1'
),
)
);
$journal_entry_lines[] = $journal_entry_line;
$journal_entry_create['Line'] = $journal_entry_lines;
$journal_entry_receipt_create = QBJournalEntry::create($journal_entry_create);
$journal_entry_receipt_create_result = $dataService->Add($journal_entry_receipt_create);
Without EntityRef its working fine but when I add EntityRef its giving me error "Message: Passed array has no key for 'Value' when contructing an ReferenceType"
Only just came across this problem myself. They did fix this issue but didn't seem to document it at all or tell anyone. Found the fix in the source code. You need to use "JournalEntryEntity" instead of "Entity" under "JournalEntryLineDetail", like so:
'JournalEntryLineDetail' => array(
'PostingType' => "Credit",
'JournalEntryEntity' => array(
'Type' => 'Customer',
'EntityRef' => array(
'value' => "2"
)
),
'AccountRef' => array(
'name' => 'Account Name',
'value' => '1'
),
)
Also I used the FacadeHelper from the V3 of the PHP SDK (I'm not sure if it'll work with the method you were using):
use QuickBooksOnline\API\Facades\FacadeHelper;
...
$journal_entry_receipt_create = FacadeHelper::reflectArrayToObject('JournalEntry', $journal_entry_create);
$journal_entry_receipt_create_result = $dataService->Add($journal_entry_receipt_create);
I know this is probably too late for you OP but hopefully it helps someone else!

Add `alt` parameter while generating reports from AdExchange Seller API

I'm trying to retrieve a report from the AdExchange Seller API.
I am using the maximum allowed amount of dimensions and metrics so the reports is quite big (>100.000 rows). According to the documentation on large reports this is possible using the limit break feature by adding the alt=media parameter. But I can't figure out how to add that parameter using the Google API client for PHP. I would prefer to stick to the official Google libraries, but I'm open for suggestions.
Note: adding alt=csv or alt=media to the optParams does not work and I can easily access the data if I remove some of the dimensions and metrics.
More specifically I'm using the accounts_reports resource and then the generate method. Looking at the source code (shown below), I can't see anywhere that it would be able to accept a alt parameter, but I'm obviously missing something.
$this->accounts_reports = new Google_Service_AdExchangeSeller_Resource_AccountsReports(
$this,
$this->serviceName,
'reports',
array(
'methods' => array(
'generate' => array(
'path' => 'accounts/{accountId}/reports',
'httpMethod' => 'GET',
'parameters' => array(
'accountId' => array(
'location' => 'path',
'type' => 'string',
'required' => true,
),
'startDate' => array(
'location' => 'query',
'type' => 'string',
'required' => true,
),
'endDate' => array(
'location' => 'query',
'type' => 'string',
'required' => true,
),
'dimension' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'filter' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'locale' => array(
'location' => 'query',
'type' => 'string',
),
'maxResults' => array(
'location' => 'query',
'type' => 'integer',
),
'metric' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'sort' => array(
'location' => 'query',
'type' => 'string',
'repeated' => true,
),
'startIndex' => array(
'location' => 'query',
'type' => 'integer',
),
),
),
)
)
);
Digging further I found this statement in the Google_Service_AdExchangeSeller_Resource_AccountsReports class.
Generate an Ad Exchange report based on the report request sent in the query
parameters. Returns the result as JSON; to retrieve output in CSV format
specify "alt=csv" as a query parameter. (reports.generate)
But how exactly would that work? As far as I can figure out, it doesn't.
Not really an answer but to long for a comment.
I don't think you are going to get that to work with the client library. The client libraries are generated via the Discovery Services API. Which gives information about what parameters the API takes. For some reason this alt=csv is not registered in the discovery services for that API. Its there in the description but its not registered as a parameter. So the Client library itself isn't going to build it for you.
You can see the response I am looking at here
An idea would be to make the change to the client library yourself you have the code. While altering the client libraries manually is not ideal it is doable.
Try and add alt and give it a value of CSV.
I don't have enough experience with the inner workings of the PHP client library but you can post this as an issue on their forum. Mention that its not in discovery they may have an easer way of applying a random parameter to the query string. I doubt it but its worth a shot.
This should be possible with the PHP client library. The following example demonstrates how to do it with the Drive API:
$fileId = '0BwwA4oUTeiV1UVNwOHItT0xfa2M';
$content = $driveService->files->get($fileId, array(
'alt' => 'media' ));
https://developers.google.com/drive/v3/web/manage-downloads#examples

aws SDK 3, PHP, runInstance does not create the supplied Tags

$options = array(
'UserData' => base64_encode('test'),
'SecurityGroupIds' => [AWS_REGIONS[$region]['security_group']],
'InstanceType' => AWS_REGIONS[$region]['instance_type'],
'ImageId' => AWS_REGIONS[$region]['ami'],
'MaxCount' => $to_launch,
'MinCount' => 1,
//'EbsOptimized' => true,
'SubnetId' => AWS_REGIONS[$region]['subnet_id'],
'Tags' => [['Key' => 'task', 'Value' => $task],['Key' => 'Name', 'Value' => $task]],
'InstanceInitiatedShutdownBehavior' => 'terminate'
);
$response = $client->runInstances($options);
I am using the "latest" Ec2Client
It launches fine but the Tags are completely ignored.
I suspect an error within the EC2 API but I am not that experienced.
Maybe someone with experience can help me out ?
This is because Ec2Client::runInstances does not have tags option
http://docs.aws.amazon.com/aws-sdk-php/v3/api/api-ec2-2015-10-01.html#runinstances
You would need to make a separate call to tag newly created instance(s) using Ec2Client::createTags:
$result = $client->createTags(array(
'DryRun' => true || false,
// Resources is required
'Resources' => array('string', ... ),
// Tags is required
'Tags' => array(
array(
'Key' => 'string',
'Value' => 'string',
),
// ... repeated
),
));
Read more here:
http://docs.aws.amazon.com/aws-sdk-php/v3/api/api-ec2-2015-10-01.html#createtags

Refactor AWS query to minimize write requests

I need to be able to write information to an AWS dynamoDB. However not every write includes the same information, but I would like to use the same code. I can make it work by making multiple requests, but I was wondering if there a way I can refactor this so it can be done with one request?
// This code makes the initial write using what is always posted.
$newRecord = $client->putItem(array(
'TableName' => 'ximoRepV3',
'Item' => array(
'rep_num' => array('S' => $rep_num),
'fc_key' => array('BOOL' => false),
...
)
));
// Then I have a series of if's for writes that are not always present.
if (!empty($salt)){
$saltUpdate = $client->updateItem ( array (
'TableName' => 'ximoRepV3',
'Key' => array (
'rep_num' => array (
'S' => $rep_num
)
),
'ExpressionAttributeValues' => array (
':salt' => array('S' => $salt)
),
'UpdateExpression' => 'SET salt = :salt'
));
}

Update TTL in existing Route53 Resource Record set

I have few A records in my Route53 Account. I want to bulk update the TTL for all of them.
The logic I'm using is that I get all the records using "ListResourceRecordSets" operation. Create following change object for each record.
array(
'Action' => 'UPSERT',
'ResourceRecordSet' => array(
'Name' => OLD_CNAME,
'Type' => 'A',
'TTL' => NEW_TTL,
'ResourceRecords' => array(array(
'Value' => OLD_IP
)),
));
Then I send a "ChangeResourceRecordSets" request with change objects created in last step.
Route53 is returning this error Validation errors: [ChangeBatch][Changes][0][Change][Action] must be one of "CREATE" or "DELETE" [ChangeBatch][Changes][1][Change][Action] must be one of "CREATE" or "DELETE" )
P.S. I couldn't find any UPSERT example for ChangeResourceRecordSets call.
Either update your AWS SDK to a later version that supports UPSERT or You first have to delete the record set(s) and then add them with the new changes.
UPSERT was added in early 2014: https://aws.amazon.com/blogs/aws/new-features-for-route-53-improved-health-checks-https-record-modification/
So you must have a really old SDK.
To do it without UPSERT:
array(
'Action' => 'DELETE',
'ResourceRecordSet' => array(
'Name' => OLD_CNAME,
'Type' => 'A',
'TTL' => OLD_TTL,
'ResourceRecords' => array(array(
'Value' => OLD_IP
)),
));
and then:
array(
'Action' => 'CREATE',
'ResourceRecordSet' => array(
'Name' => OLD_CNAME,
'Type' => 'A',
'TTL' => NEW_TTL,
'ResourceRecords' => array(array(
'Value' => OLD_IP
)),
));

Categories