68
November 12, 2014 | Las Vegas, NV Jeremy Lindblom (@jeremeamia), AWS Developer Resources @awsforphp

(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Embed Size (px)

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.

Citation preview

Page 1: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

November 12, 2014 | Las Vegas, NV

Jeremy Lindblom (@jeremeamia), AWS Developer Resources

@awsforphp

Page 2: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

1. Introduce the SDK (including Version 3)

2. Build an app with the SDK

3. Demonstrate advanced SDK features

Page 3: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 4: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$ec2 = ::factory

'region' => 'us-east-1'

'version' => '2014-06-15'

$ec2->runInstances

'ImageId' => 'ami-6a6dcc02'

'MinCount' =>

'MaxCount' =>

'InstanceType' => 'm1.small'

Page 5: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 6: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

(semver.org)

Page 7: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 8: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

(cont.)

Page 9: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$ec2 = ::factory

'region' => 'us-east-1'

$ec2->runInstances

'ImageId' => 'ami-6a6dcc02'

'MinCount' =>

'MaxCount' =>

'InstanceType' => 'm1.small'

Page 10: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$ec2 = ::factory

'region' => 'us-east-1'

$ec2->runInstances

'ImageId' => 'ami-6a6dcc02'

'MinCount' =>

'MaxCount' =>

'InstanceType' => 'm1.small'

'version' => '2014-06-15'

Page 11: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• 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

Page 12: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 13: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP PHP

#nofilter

#selphpie

#instagood

Page 14: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP PHP

Page 15: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

(Storage of selPHPies)

(Storage of URLs/captions)PHP

PHP

Page 16: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 17: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

"require": {

"aws/aws-sdk-php": "~3.0@dev",

"silex/silex": "~1.2",

"twig/twig": "~1.16",

}

getcomposer.org

Page 18: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• Instance profile credentials

• Credentials file

• Environment variables

• Hard coding

Page 19: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• Instance profile credentials

• Credentials file

• Environment variables

• Client configuration

Page 20: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• Instance profile credentials

• Credentials file

• Environment variables

• Client configuration

FYI: Also supported by the

AWS CLI and other SDKs.

Page 21: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• Instance profile credentials

• Credentials file

• Environment variables

• Client configuration

Page 22: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

• Instance profile credentials

• Credentials file

• Environment variables

• Client Configuration (BEWARE)

'credentials' =>

'key' => $yourAccessKeyId

'secret' => $yourSecretAccessKey

Page 23: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 24: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

php bin/setup.php

S3 bucket

DynamoDB table

Amazon S3Amazon

DynamoDB

Page 25: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$s3->createBucket 'Bucket' => $bucket

$s3->waitUntil 'BucketExists' 'Bucket' => $bucket

$dynamoDb->createTable(['TableName' => $table ...

$dynamoDb->waitUntil 'TableExists'

'TableName' => $table

echo "Done.\n"

Page 26: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 27: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 28: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$result = $dynamoDb->createTable([

'TableName' => $table,

'@future' => true,

]);

// Do other things...

// Blocks once dereferenced.

$result['TableDescription']['TableStatus'];

Page 29: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$waiter = $dynamoDb->getWaiter(

'TableExists', [...]

);

$waiter->wait();

// THIS IS THE SAME AS:

$dynamoDb->waitUntil 'TableExists' ...

Page 30: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$result = $client->operation([...]);

$result->then(

$onFulfilled,

$onRejected,

$onProgress,

);

// See the React/Promise library

Page 31: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$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";

});

Page 32: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$dynamoDb->createTable([…])

->then(...)

->then(...);

$s3->createBucket([…])

->then(...)

->then(...);

Page 33: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 34: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$app = new

$app 'aws' = function

return new

'region' => 'us-east-1'

'version' => 'latest'

// ROUTES AND OTHER APPLICATION LOGIC

$app->run

Page 35: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$app->get '/' function ...

Page 36: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$dynamoDb = $app 'aws' ->getDynamoDb

$result = $dynamoDb->query

'TableName' => 'selphpies'

'Limit' =>

// ...

$items = $result 'Items'

Page 37: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$results = $dynamoDb->getPaginator 'Query'

'TableName' => 'selphpies'

// ...

$items = $results->search 'Items[]'

Page 38: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$results = $s3->getPaginator 'ListObjects' ...

$files = $results->search 'Contents[].Key'

Page 39: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

# 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'

Page 40: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

http://jmespath.org/

$result->search '<JMESPath Expression>'

> 'Contents[].Key'

> '[CommonPrefixes[].Prefix, Contents[].Key][]'

> 'NextMarker || Contents[-1].Key'

Page 41: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$app->get '/upload' function ...

Page 42: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

POST

$app->post '/upload' function ...

Page 43: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

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');

}

Page 44: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$s3 = $app['aws']->getS3();

$result = $s3->putObject([

'Bucket' => 'selphpies',

'Key' => $file->getClientOriginalName(),

'Body' => fopen($file->getFileName(), 'r'),

'ACL' => 'public-read',

]);

Page 45: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

// 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'

);

Page 46: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$dynamoDb->putItem([

'TableName' => 'selphpies',

'Item' => [

// ...

'src' => ['S' => $result['ObjectURL']],

'caption' => ['S' => $caption],

],

]);

Page 47: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

such php

so cloud

wow

very selfie

much app

#phpdoge

Page 48: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Page 49: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Really

Page 50: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Page 51: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Page 52: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Page 53: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Step 1

Step 2Step 3 Step 4

Page 54: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Step 1

Page 55: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$results = $dynamoDb->getPaginator 'Scan'

'TableName' => $oldTable

'KeyConditions' =>

Page 56: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Step 2

Page 57: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$records = new $dynamoDb

'table' => $newTable

// $records->put($selphpie);

$records->flush

Page 58: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Step 3

Page 59: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$commands =

$commands = $s3->getCommand 'CopyObject' ...

$commands = $s3->getCommand 'CopyObject' ...

$commands = $s3->getCommand 'CopyObject' ...

// ...

$s3->executeAll $commands

Page 60: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$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

Page 61: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

Step 4

Page 62: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

$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...

Page 63: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

PHP

Step 1

Step 2Step 3 Step 4

Page 64: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

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();

Page 65: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Page 66: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

@awsforphp

github.com/aws/aws-sdk-php/releases

blogs.aws.amazon.com/php

Page 67: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

github.com/aws/aws-sdk-php

forums.aws.amazon.com

Page 68: (DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014

http://bit.ly/awsevals

@awsforphp

Come find us at the AWS booths

if you have questions.

Your Homework: