Install the Bundle
composer require async-aws/async-aws-bundle
Add to config/bundles.php:
return [
// ...
AsyncAws\Bundle\AsyncAwsBundle::class => ['all' => true],
];
Configure AWS Clients
Define clients in config/packages/async_aws.yaml:
async_aws:
clients:
s3:
region: 'eu-west-1'
version: 'latest'
credentials:
key: '%env(AWS_ACCESS_KEY_ID)%'
secret: '%env(AWS_SECRET_ACCESS_KEY)%'
Autowire a Client Inject the client directly into a service:
use AsyncAws\S3\S3Client;
class MyService {
public function __construct(private S3Client $s3) {}
}
use AsyncAws\S3\S3Client;
use AsyncAws\S3\Enum\CannedAcl;
class FileUploader {
public function __construct(private S3Client $s3) {}
public function upload(string $filePath, string $bucket, string $key): void
{
$this->s3->putObject([
'Bucket' => $bucket,
'Key' => $key,
'Body' => fopen($filePath, 'r'),
'ACL' => CannedAcl::PUBLIC_READ,
]);
}
}
Use Symfony’s environment-aware config (e.g., config/packages/async_aws_{env}.yaml) to override settings per environment:
# config/packages/async_aws_prod.yaml
async_aws:
clients:
s3:
region: 'us-east-1'
credentials:
provider: 'ssm' # Use SSM for credentials in production
Leverage built-in providers (e.g., SSM, IAM roles) or custom ones:
async_aws:
clients:
dynamodb:
credentials:
provider: 'ssm'
provider_options:
parameter_name: '/aws/credentials/dynamodb'
region: 'eu-west-1'
Attach middleware (e.g., logging, retries) globally or per client:
async_aws:
clients:
sqs:
middleware:
- AsyncAws\Common\Middleware\RetryMiddleware
- AsyncAws\Common\Middleware\LoggerMiddleware
Combine with Symfony’s Messenger for async workflows:
use AsyncAws\SQS\SQSClient;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class ProcessSqsMessage {
public function __construct(private SQSClient $sqs) {}
public function __invoke(string $message): void
{
$this->sqs->sendMessage([
'QueueUrl' => 'https://sqs.eu-west-1.amazonaws.com/...',
'MessageBody' => json_encode(['processed' => true]),
]);
}
}
Use AsyncAws\Bundle\Test\AsyncAwsExtension for mocking AWS responses:
use AsyncAws\Bundle\Test\AsyncAwsExtension;
use AsyncAws\S3\S3Client;
class MyServiceTest extends TestCase {
use AsyncAwsExtension;
public function testUpload(): void
{
$this->mockS3Client()
->putObject()
->returns(['ETag' => 'abc123']);
$service = new MyService($this->getS3Client());
$service->upload('file.txt', 'bucket', 'key');
}
}
Credential Conflicts
Avoid mixing credentials.key/secret with credentials.provider. The bundle prioritizes the latter if both are set.
Fix: Remove redundant key/secret when using providers like SSM.
Region Mismatches
Ensure the region in your config matches the AWS service’s actual region (e.g., us-east-1 vs. eu-west-1).
Tip: Use aws configure list-regions to verify.
Middleware Order
Middleware runs in the order defined. Place RetryMiddleware before LoggerMiddleware to avoid logging retries.
Example:
middleware:
- AsyncAws\Common\Middleware\RetryMiddleware
- AsyncAws\Common\Middleware\LoggerMiddleware
Caching Quirks Credential caching (enabled by default) may cause stale credentials if AWS IAM roles rotate. Workaround: Disable caching for short-lived roles:
async_aws:
credential:
cache: false
Enable Logging
Add the async_aws channel to monolog.yaml:
monolog:
channels: ['async_aws']
handlers:
async_aws:
type: stream
path: "%kernel.logs_dir%/async_aws.log"
level: debug
VarDumper Integration
Use AsyncAws\Bundle\VarDumper\AsyncAwsDumper to inspect AWS responses:
use AsyncAws\Bundle\VarDumper\AsyncAwsDumper;
class DebugController {
public function __invoke(AsyncAwsDumper $dumper, S3Client $s3): void
{
$response = $s3->listBuckets();
$dumper->dump($response);
}
}
Configuration Validation
Run php bin/console debug:config async_aws to validate your config structure.
Custom Clients
Extend the bundle to support non-AWS services by creating a custom ClientFactory:
use AsyncAws\Bundle\DependencyInjection\ClientFactoryInterface;
class CustomClientFactory implements ClientFactoryInterface {
public function create(string $name, array $config): object {
return new CustomAwsClient($config);
}
}
Register it in services.yaml:
services:
AsyncAws\Bundle\DependencyInjection\ClientFactoryInterface:
class: App\CustomClientFactory
tags: ['async_aws.client_factory']
Dynamic Configs
Override the Configuration class to add custom options:
use AsyncAws\Bundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
class AppConfiguration extends Configuration {
protected function getConfigTreeBuilder(): TreeBuilder {
$tree = parent::getConfigTreeBuilder();
$tree->rootNode()
->children()
->scalarNode('custom_option')->defaultValue('default')->end()
->end();
return $tree;
}
}
Update config/packages/async_aws.yaml:
async_aws:
custom_option: 'my_value'
Event Listeners
Subscribe to AWS events (e.g., AsyncAws\Common\Event\BeforeRequestEvent):
use AsyncAws\Common\Event\BeforeRequestEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(BeforeRequestEvent::class)]
class AddCustomHeaderListener {
public function __invoke(BeforeRequestEvent $event): void {
$event->getRequest()->addHeader('X-Custom-Header', 'value');
}
}
How can I help you explore Laravel packages today?