(dev305) building apps with the aws sdk for php | aws re:invent 2014
DESCRIPTION
For both new and experienced users of the AWS SDK for PHP, we highlight features of the SDK as we work through building a simple, scalable PHP application. Attendees will learn about core features of the SDK including service clients, iterators, and waiters. We will also introduce new features in the upcoming Version 3 of the SDK, including asynchronous requests, paginators, and the new JMESPath result querying syntax.TRANSCRIPT
November 12, 2014 | Las Vegas, NV
Jeremy Lindblom (@jeremeamia), AWS Developer Resources
@awsforphp
1. Introduce the SDK (including Version 3)
2. Build an app with the SDK
3. Demonstrate advanced SDK features
$ec2 = ::factory
'region' => 'us-east-1'
'version' => '2014-06-15'
$ec2->runInstances
'ImageId' => 'ami-6a6dcc02'
'MinCount' =>
'MaxCount' =>
'InstanceType' => 'm1.small'
(semver.org)
(cont.)
$ec2 = ::factory
'region' => 'us-east-1'
$ec2->runInstances
'ImageId' => 'ami-6a6dcc02'
'MinCount' =>
'MaxCount' =>
'InstanceType' => 'm1.small'
$ec2 = ::factory
'region' => 'us-east-1'
$ec2->runInstances
'ImageId' => 'ami-6a6dcc02'
'MinCount' =>
'MaxCount' =>
'InstanceType' => 'm1.small'
'version' => '2014-06-15'
• Async requests with Future Result
objects and a Promise API
• Support for custom HTTP adapters
– cURL no longer required (still the default)
– Possible to implement with non-blocking event loops
• Result "Paginators" for iterating paginated data
• JMESPath querying of result data
• "debug" client option for easy debugging
PHP PHP
#nofilter
#selphpie
#instagood
PHP PHP
(Storage of selPHPies)
(Storage of URLs/captions)PHP
PHP
"require": {
"aws/aws-sdk-php": "~3.0@dev",
"silex/silex": "~1.2",
"twig/twig": "~1.16",
}
getcomposer.org
• Instance profile credentials
• Credentials file
• Environment variables
• Hard coding
• Instance profile credentials
• Credentials file
• Environment variables
• Client configuration
• Instance profile credentials
• Credentials file
• Environment variables
• Client configuration
FYI: Also supported by the
AWS CLI and other SDKs.
• Instance profile credentials
• Credentials file
• Environment variables
• Client configuration
• Instance profile credentials
• Credentials file
• Environment variables
• Client Configuration (BEWARE)
'credentials' =>
'key' => $yourAccessKeyId
'secret' => $yourSecretAccessKey
php bin/setup.php
S3 bucket
DynamoDB table
Amazon S3Amazon
DynamoDB
$s3->createBucket 'Bucket' => $bucket
$s3->waitUntil 'BucketExists' 'Bucket' => $bucket
$dynamoDb->createTable(['TableName' => $table ...
$dynamoDb->waitUntil 'TableExists'
'TableName' => $table
echo "Done.\n"
$result = $dynamoDb->createTable([
'TableName' => $table,
'@future' => true,
]);
// Do other things...
// Blocks once dereferenced.
$result['TableDescription']['TableStatus'];
$waiter = $dynamoDb->getWaiter(
'TableExists', [...]
);
$waiter->wait();
// THIS IS THE SAME AS:
$dynamoDb->waitUntil 'TableExists' ...
$result = $client->operation([...]);
$result->then(
$onFulfilled,
$onRejected,
$onProgress,
);
// See the React/Promise library
$dynamoDb->createTable([
'TableName' => $table,
'@future' => true,
])->then(function ($result) use ($dynamoDb, $table) {
return $dynamoDb->getWaiter('TableExists', [
'TableName' => $table,
])->promise();
})->then(function ($result) {
echo "Done.\n";
});
$dynamoDb->createTable([…])
->then(...)
->then(...);
$s3->createBucket([…])
->then(...)
->then(...);
$app = new
$app 'aws' = function
return new
'region' => 'us-east-1'
'version' => 'latest'
// ROUTES AND OTHER APPLICATION LOGIC
$app->run
$app->get '/' function ...
$dynamoDb = $app 'aws' ->getDynamoDb
$result = $dynamoDb->query
'TableName' => 'selphpies'
'Limit' =>
// ...
$items = $result 'Items'
$results = $dynamoDb->getPaginator 'Query'
'TableName' => 'selphpies'
// ...
$items = $results->search 'Items[]'
$results = $s3->getPaginator 'ListObjects' ...
$files = $results->search 'Contents[].Key'
# With Paginators
$results = $s3->getPaginator 'ListObjects'
'Bucket' => 'my-bucket'
$keys = $results->search 'Contents[].Key'
foreach $keys as $key
echo $object 'Key' . "\n"
# Without Paginators
$marker =
do
$args = 'Bucket' => 'my-bucket'
if $marker
$args 'Marker' = $marker
$result = $s3->listObjects $args
$objects = array $result 'Contents'
foreach $objects as $object
echo $object 'Key' . "\n"
$marker $result->search
'NextMarker || Contents[-1].Key'
while $result 'IsTruncated'
http://jmespath.org/
$result->search '<JMESPath Expression>'
> 'Contents[].Key'
> '[CommonPrefixes[].Prefix, Contents[].Key][]'
> 'NextMarker || Contents[-1].Key'
$app->get '/upload' function ...
POST
$app->post '/upload' function ...
try {
$caption = $request->request->get('selphpieCaption', '...');
$file = $request->files->get('selphpieImage');
if (!$file instanceof UploadedFile || $file->getError()) {
throw new \RuntimeException('...');
}
#1. UPLOAD THE IMAGE TO S3
#2. SAVE THE IMAGE DATA TO DYNAMODB$app['session']->getFlashBag()->add('alerts', 'success');
return $app->redirect('/');
} catch (\Exception $e) {
$app['session']->getFlashBag()->add('alerts', 'danger');
return $app->redirect('/upload');
}
$s3 = $app['aws']->getS3();
$result = $s3->putObject([
'Bucket' => 'selphpies',
'Key' => $file->getClientOriginalName(),
'Body' => fopen($file->getFileName(), 'r'),
'ACL' => 'public-read',
]);
// Automatically switches to multipart uploads
// if the file is larger than default threshold.
$result = $s3->upload(
'selphpies',
$file->getClientOriginalName(),
fopen($file->getPathname(), 'r'),
'public-read'
);
$dynamoDb->putItem([
'TableName' => 'selphpies',
'Item' => [
// ...
'src' => ['S' => $result['ObjectURL']],
'caption' => ['S' => $caption],
],
]);
PHP
such php
so cloud
wow
very selfie
much app
#phpdoge
PHP
Really
PHP
PHP
PHP
PHP
Step 1
Step 2Step 3 Step 4
Step 1
$results = $dynamoDb->getPaginator 'Scan'
'TableName' => $oldTable
'KeyConditions' =>
Step 2
$records = new $dynamoDb
'table' => $newTable
// $records->put($selphpie);
$records->flush
Step 3
$commands =
$commands = $s3->getCommand 'CopyObject' ...
$commands = $s3->getCommand 'CopyObject' ...
$commands = $s3->getCommand 'CopyObject' ...
// ...
$s3->executeAll $commands
$getCopyCommands = function $results use ...
foreach $results->search 'Items[]' as $selphpie
$command = $s3->getCommand 'CopyObject'
'Bucket' => $newBucket
'Key' => $key
'SourceFile' => "{$oldBucket}/{$key}"
// ... (Attach event listener in Step 4) ...
yield $command
$s3->executeAll $getCopyCommands $results
Step 4
$emitter = $command->getEmitter
$emitter->on 'process' function $event use ...
if $result = $event->getResult
$selphpie 'url' 'S' = $result 'ObjectURL'
// Add new record to WriteRequestBatch
$records->put $selphpie
else
// Log/handle error...
PHP
Step 1
Step 2Step 3 Step 4
PHP
$results = $dynamoDb->getPaginator('Scan', [
'TableName' => $oldBucket,
'KeyConditions' => [
'app' => [
'AttributeValueList' => [['S' => $oldAppKey]],
'ComparisonOperator' => 'EQ',
],
],
]);
$records = new WriteRequestBatch($dynamoDb, [
'table' => $newTable
]);
$getCopyCommands = function ($results) use (
$s3, $records, $oldBucket, $newBucket, $newAppKey
) {
foreach ($results->search('Items[]') as $selphpie) {
$key = Url::fromString($selphpie['url']['S'])->getPath();
$command = $s3->getCommand('CopyObject', [
'Bucket' => $newBucket,
'Key' => $key,
'SourceFile' => "{$oldBucket}/{$key}",
]);
$emitter = $command->getEmitter();
$emitter->on('process', function ($event) use (
$selphpie, $records, $newAppKey
) {
if ($result = $event->getResult()) {
$selphpie['url']['S'] = $result['ObjectURL'];
$selphpie['app']['S'] = $newAppKey;
// Add new record to WriteRequestBatch
$records->put($selphpie);
} else {
// Log/handle error...
}
});
yield $command;
}
};
$s3->executeAll($getCopyCommands($results));
$records->flush();
@awsforphp
github.com/aws/aws-sdk-php/releases
blogs.aws.amazon.com/php
github.com/aws/aws-sdk-php
forums.aws.amazon.com
http://bit.ly/awsevals
@awsforphp
Come find us at the AWS booths
if you have questions.
Your Homework: