seferov/aws-bundle
A Symfony bundle that integrates the AWS SDK for PHP, configuring services such as S3, SQS, and DynamoDB as container services. It simplifies credentials and lets Symfony apps inject AWS clients via dependency injection.
The package is a thin Symfony bundle around aws/aws-sdk-php. It does two things: pulls the Aws\Sdk construction into YAML config, and registers one lazy service per named client. That is the whole value proposition — so the first thing to check is whether you actually need it versus wiring the SDK yourself in a service definition.
Install (Symfony 2/3/4 only):
composer require seferov/aws-bundle
Register Seferov\AwsBundle\SeferovAwsBundle in AppKernel.php (Symfony 2/3) or config/bundles.php (Symfony 4).
Minimal config — config/packages/seferov_aws.yaml:
seferov_aws:
sdk:
region: eu-west-1
version: latest
clients:
s3: ~
First use case — inject the named client and use the raw SDK:
use Aws\S3\S3Client;
class Uploader
{
public function __construct(private S3Client $s3) {}
public function put(string $key, string $body): void
{
$this->s3->putObject([
'Bucket' => 'my-bucket',
'Key' => $key,
'Body' => $body,
]);
}
}
# services.yaml
App\Uploader:
arguments:
$s3: '@seferov_aws.client.s3'
Where to look first, in order:
DependencyInjection/Configuration.php — the exact config shape (the README is thin; the config tree is the real contract).Aws/ClientFactory.php — how client names resolve to SDK client classes.Resources/config/services.yml — the real service IDs (seferov_aws.client_factory, seferov_aws.client.<name>).bin/console debug:container seferov_aws --show-private to confirm what actually got registered in your app.Laravel note: this cannot be installed into a Laravel app. There is no service provider, and the bundle's DI extensions and Resources/config are Symfony-specific. The day-to-day equivalent in Laravel is a singleton binding of Aws\Sdk (or per-client bindings) in a service provider — see the patterns below, which transfer almost 1:1.
Named clients for multi-region / multi-account. The common pattern is one client per combination, aliased by intent rather than service:
seferov_aws:
sdk:
region: eu-west-1
version: '2006-03-01'
clients:
s3_assets: { region: eu-west-1 }
s3_backups: { region: us-east-1 }
sqs_jobs: { region: eu-west-1 }
Then inject @seferov_aws.client.s3_backups where needed. This is the bundle's best feature: region and credentials stay in config, not constructor calls.
Factory for dynamic selection. When the client name is computed (tenant, queue environment), inject seferov_aws.client_factory and resolve at runtime:
public function __construct(private ClientFactory $clients) {}
public function queue(string $env): AwsClient
{
return $this->clients->get('sqs_' . $env);
}
This is the integration point to wrap in your own service — never let raw AWS clients leak into controllers.
Credentials via the default chain, not YAML. Leave key/secret out of sdk so the SDK falls back to env vars, IAM instance role, or ~/.aws/credentials. Only put static credentials in config for local/dev, and read them from %env(...)% so they never land in var/cache.
Per-client override of SDK defaults. Anything under sdk is passed to the Aws\Sdk constructor; anything under a client's own key is merged over it. So set region, version, http, and handler globally and override only what differs per client. sdk.handler is the cleanest way to inject a mock handler or custom Guzzle stack in tests.
Local development against LocalStack / moto. Add a dev-only client with endpoint and path-style addressing, and point your services at that alias via config/packages/dev/:
seferov_aws:
clients:
s3:
endpoint: 'http://localhost:4566'
use_path_style_endpoint: true
Testing. Because the bundle registers concrete SDK classes, prefer injecting ClientFactory in code you need to unit test and swapping that service in the test container, or configure sdk.handler with Aws\MockHandler in a test-only config file. Trying to mock S3Client directly is miserable.
Laravel translation of the same pattern: bind each client as a singleton keyed by name, and a small AwsClientFactory that reads a config/aws.php map. The bundle's design — config tree + factory + named services — is exactly what you'd write yourself in a service provider, minus the Symfony plumbing.
aws/aws-sdk-php to an old release on modern projects, or to fork the bundle. The code is small enough that forking/vendoring ClientFactory is usually the better move than adopting the bundle at all.Aws\S3\S3Client, so type-hinting S3Client will not resolve. Always bind by service id (@seferov_aws.client.s3) or alias per class.version: latest costs a network round trip. The SDK resolves the API version against the service on first client build unless you pin one. In production that means either a startup latency hit or a credentials/permissions failure at an awkward moment. Pin the version string.key/secret in YAML is compiled into var/cache and visible via debug:container. Use %env()% at minimum; the default provider chain is better.bin/console debug:container seferov_aws.client.<name> after editing.region inherits from sdk — easy to miss when you add a second client and assume it picked up something else. Cross-region 301/PermanentRedirect errors are usually this.Aws\Exception\AwsException. Retry logic, backoff, and circuit-breaking are your responsibility; the bundle adds nothing.Aws\Sdk constructor accepts (http, handler, credentials, endpoint, use_path_style_endpoint, profile) can go under sdk; everything an individual client constructor accepts can go under the client entry. There is no bundle-specific plugin system — that's the entire surface area to learn.seferov/aws-bundle is unrelated to similarly named AWS bundles. Don't install two and expect shared clients or shared credentials.How can I help you explore Laravel packages today?