From 0a353453bd641fcb35341af36de5358314ecf9b8 Mon Sep 17 00:00:00 2001 From: spiralbot Date: Wed, 13 Dec 2023 18:52:16 +0000 Subject: [PATCH] Merge pull request #1029 from spiral/bugfix/storage-adapter --- src/Config/StorageConfig.php | 52 +++++++------ tests/Config/StorageConfigTest.php | 115 ++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 22 deletions(-) diff --git a/src/Config/StorageConfig.php b/src/Config/StorageConfig.php index c8ff16c..a601e12 100644 --- a/src/Config/StorageConfig.php +++ b/src/Config/StorageConfig.php @@ -138,25 +138,13 @@ private function createAdapter(string $serverName, array $bucket, array $server) private function createS3Adapter(string $serverName, array $bucket, array $server, bool $async): FilesystemAdapter { - if (!\class_exists(Credentials::class)) { + if (!$async && !\class_exists(Credentials::class)) { throw new ConfigException( 'Can not create AWS credentials while creating "' . $serverName . '" server. ' . 'Perhaps you forgot to install the "league/flysystem-aws-s3-v3" package?' ); } - $config = [ - 'version' => $server['version'] ?? 'latest', - 'region' => $bucket['region'] ?? $server['region'] ?? null, - 'endpoint' => $server['endpoint'] ?? null, - 'credentials' => new Credentials( - $server['key'] ?? null, - $server['secret'] ?? null, - $server['token'] ?? null, - $server['expires'] ?? null - ), - ] + ($server['options'] ?? []); - $name = $bucket['bucket'] ?? $server['bucket']; $visibility = $bucket['visibility'] ?? $server['visibility'] ?? Visibility::VISIBILITY_PUBLIC; @@ -168,12 +156,10 @@ private function createS3Adapter(string $serverName, array $bucket, array $serve } return new AsyncAwsS3Adapter( - new S3AsyncClient($config), + new S3AsyncClient($this->createAwsConfig($bucket, $server, true)), $name, $bucket['prefix'] ?? $server['prefix'] ?? '', - new AsyncAwsS3PortableVisibilityConverter( - $visibility - ) + new AsyncAwsS3PortableVisibilityConverter($visibility) ); } @@ -184,12 +170,10 @@ private function createS3Adapter(string $serverName, array $bucket, array $serve } return new AwsS3V3Adapter( - new S3Client($config), + new S3Client($this->createAwsConfig($bucket, $server)), $name, $bucket['prefix'] ?? $server['prefix'] ?? '', - new AwsS3PortableVisibilityConverter( - $visibility - ) + new AwsS3PortableVisibilityConverter($visibility) ); } @@ -242,4 +226,30 @@ private function createCustomAdapter(string $serverName, array $server): Filesys throw new InvalidArgumentException(\sprintf($message, $serverName, $e->getMessage()), 0, $e); } } + + private function createAwsConfig(array $bucket, array $server, bool $async = false): array + { + $config = [ + 'region' => $bucket['region'] ?? $server['region'] ?? null, + 'endpoint' => $server['endpoint'] ?? null, + ] + ($server['options'] ?? []); + + if (!$async) { + $config['version'] = $server['version'] ?? 'latest'; + $config['credentials'] = new Credentials( + $server['key'] ?? null, + $server['secret'] ?? null, + $server['token'] ?? null, + $server['expires'] ?? null + ); + + return $config; + } + + $config['accessKeyId'] = $server['key'] ?? null; + $config['accessKeySecret'] = $server['secret'] ?? null; + $config['sessionToken'] = $server['token'] ?? null; + + return $config; + } } diff --git a/tests/Config/StorageConfigTest.php b/tests/Config/StorageConfigTest.php index 9fc03bb..0b6d300 100644 --- a/tests/Config/StorageConfigTest.php +++ b/tests/Config/StorageConfigTest.php @@ -4,10 +4,13 @@ namespace Spiral\Tests\Storage\Config; +use AsyncAws\S3\S3Client as S3AsyncClient; use Aws\Credentials\Credentials; use Aws\S3\S3Client; +use League\Flysystem\AsyncAwsS3\AsyncAwsS3Adapter; use League\Flysystem\AwsS3V3\AwsS3V3Adapter; use League\Flysystem\AwsS3V3\PortableVisibilityConverter as AwsS3PortableVisibilityConverter; +use League\Flysystem\AsyncAwsS3\PortableVisibilityConverter as AsyncAwsS3PortableVisibilityConverter; use PHPUnit\Framework\TestCase; use Spiral\Storage\Config\StorageConfig; use Spiral\Storage\Visibility; @@ -46,6 +49,24 @@ public function testS3Adapter(): void ), $config->getAdapters()['uploads']); } + public function testS3AsyncAdapter(): void + { + $config = new StorageConfig($this->getConfig()); + + $this->assertEquals(new AsyncAwsS3Adapter( + new S3AsyncClient([ + 'region' => 'test-region', + 'endpoint' => 'test-endpoint', + 'accessKeyId' => 'test-key', + 'accessKeySecret' => 'test-secret', + 'sessionToken' => null, + ]), + 'test-bucket', + 'test-prefix', + new AsyncAwsS3PortableVisibilityConverter(Visibility::VISIBILITY_PUBLIC) + ), $config->getAdapters()['uploads-async']); + } + public function testS3AdapterWithOverriddenBucket(): void { $config = new StorageConfig($this->getConfig(['buckets' => [ @@ -71,6 +92,26 @@ public function testS3AdapterWithOverriddenBucket(): void ), $config->getAdapters()['uploads']); } + public function testS3AsyncAdapterWithOverriddenBucket(): void + { + $config = new StorageConfig($this->getConfig(['buckets' => [ + 'uploads-async' => ['server' => 's3-async', 'bucket' => 'overridden'] + ]])); + + $this->assertEquals(new AsyncAwsS3Adapter( + new S3AsyncClient([ + 'region' => 'test-region', + 'endpoint' => 'test-endpoint', + 'accessKeyId' => 'test-key', + 'accessKeySecret' => 'test-secret', + 'sessionToken' => null, + ]), + 'overridden', + 'test-prefix', + new AsyncAwsS3PortableVisibilityConverter(Visibility::VISIBILITY_PUBLIC) + ), $config->getAdapters()['uploads-async']); + } + public function testS3AdapterWithOverriddenRegion(): void { $config = new StorageConfig($this->getConfig(['buckets' => [ @@ -96,6 +137,26 @@ public function testS3AdapterWithOverriddenRegion(): void ), $config->getAdapters()['uploads']); } + public function testS3AsyncAdapterWithOverriddenRegion(): void + { + $config = new StorageConfig($this->getConfig(['buckets' => [ + 'uploads-async' => ['server' => 's3-async', 'region' => 'overridden'] + ]])); + + $this->assertEquals(new AsyncAwsS3Adapter( + new S3AsyncClient([ + 'region' => 'overridden', + 'endpoint' => 'test-endpoint', + 'accessKeyId' => 'test-key', + 'accessKeySecret' => 'test-secret', + 'sessionToken' => null, + ]), + 'test-bucket', + 'test-prefix', + new AsyncAwsS3PortableVisibilityConverter(Visibility::VISIBILITY_PUBLIC) + ), $config->getAdapters()['uploads-async']); + } + public function testS3AdapterWithOverriddenVisibility(): void { $config = new StorageConfig($this->getConfig(['buckets' => [ @@ -121,6 +182,26 @@ public function testS3AdapterWithOverriddenVisibility(): void ), $config->getAdapters()['uploads']); } + public function testS3AsyncAdapterWithOverriddenVisibility(): void + { + $config = new StorageConfig($this->getConfig(['buckets' => [ + 'uploads-async' => ['server' => 's3-async', 'visibility' => Visibility::VISIBILITY_PRIVATE] + ]])); + + $this->assertEquals(new AsyncAwsS3Adapter( + new S3AsyncClient([ + 'region' => 'test-region', + 'endpoint' => 'test-endpoint', + 'accessKeyId' => 'test-key', + 'accessKeySecret' => 'test-secret', + 'sessionToken' => null, + ]), + 'test-bucket', + 'test-prefix', + new AsyncAwsS3PortableVisibilityConverter(Visibility::VISIBILITY_PRIVATE) + ), $config->getAdapters()['uploads-async']); + } + public function testS3AdapterWithOverriddenPrefix(): void { $config = new StorageConfig($this->getConfig(['buckets' => [ @@ -146,6 +227,26 @@ public function testS3AdapterWithOverriddenPrefix(): void ), $config->getAdapters()['uploads']); } + public function testS3AsyncAdapterWithOverriddenPrefix(): void + { + $config = new StorageConfig($this->getConfig(['buckets' => [ + 'uploads-async' => ['server' => 's3-async', 'prefix' => 'overridden'] + ]])); + + $this->assertEquals(new AsyncAwsS3Adapter( + new S3AsyncClient([ + 'region' => 'test-region', + 'endpoint' => 'test-endpoint', + 'accessKeyId' => 'test-key', + 'accessKeySecret' => 'test-secret', + 'sessionToken' => null, + ]), + 'test-bucket', + 'overridden', + new AsyncAwsS3PortableVisibilityConverter(Visibility::VISIBILITY_PUBLIC) + ), $config->getAdapters()['uploads-async']); + } + private function getConfig(array $config = []): array { return $config + [ @@ -161,11 +262,23 @@ private function getConfig(array $config = []): array 'prefix' => 'test-prefix', 'options' => ['use_path_style_endpoint' => true], ], + 's3-async' => [ + 'adapter' => 's3-async', + 'endpoint' => 'test-endpoint', + 'region' => 'test-region', + 'bucket' => 'test-bucket', + 'key' => 'test-key', + 'secret' => 'test-secret', + 'prefix' => 'test-prefix', + ], ], 'buckets' => [ 'uploads' => [ 'server' => 's3', - ] + ], + 'uploads-async' => [ + 'server' => 's3-async', + ], ] ]; }