diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 92fa1da..3c73ef8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -63,6 +63,10 @@ jobs: composer config --global --no-plugins allow-plugins.symfony/flex true composer global require --no-progress --no-scripts --no-plugins symfony/flex + - name: Remove azure-oss/storage-blob-flysystem when not compatible + if: matrix.php-version == '8.0' + run: sed -i "/\bazure-oss\/storage-blob-flysystem\b/d" composer.json + - name: Install Composer dependencies uses: ramsey/composer-install@v2 diff --git a/README.md b/README.md index 1307347..222673b 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ to interact with your storage. [AsyncAws S3](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#asyncaws-s3), [AWS SDK S3](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#aws-sdk-s3), [Azure](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#azure), + [Azure OSS](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#azure-oss), [Google Cloud Storage](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#google-cloud-storage), [DigitalOcean Spaces](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#digitalocean-spaces), [Scaleway Object Storage](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#scaleway-object-storage) diff --git a/composer.json b/composer.json index 772faad..9548836 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,7 @@ "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { + "azure-oss/storage-blob-flysystem": "^1.2", "doctrine/mongodb-odm": "^2.0", "league/flysystem-async-aws-s3": "^3.1", "league/flysystem-aws-s3-v3": "^3.1", diff --git a/docs/2-cloud-storage-providers.md b/docs/2-cloud-storage-providers.md index 7a4e5d2..5fe776e 100644 --- a/docs/2-cloud-storage-providers.md +++ b/docs/2-cloud-storage-providers.md @@ -5,6 +5,7 @@ including many cloud storage providers. This bundle provides the same level of s cloud providers by providing corresponding adapters in the configuration. * [Azure](#azure) +* [Azure OSS](#azure-oss) * [AsyncAws S3](#asyncaws-s3) * [AWS S3](#aws-sdk-s3) * [DigitalOcean Spaces](#digitalocean-spaces) @@ -35,6 +36,36 @@ flysystem: prefix: 'optional/path/prefix' ``` +## Azure OSS + +### Installation + +``` +composer require azure-oss/storage-blob-flysystem +``` + +### Usage + +```yaml +# config/packages/flysystem.yaml + +services: + azure_blob_storage_client: + class: 'AzureOss\Storage\Blob\BlobServiceClient' + factory: ['AzureOss\Storage\Blob\BlobServiceClient', 'fromConnectionString'] + arguments: + - '%env(AZURE_BLOB_STORAGE_CONNECTION_STRING)%' + +flysystem: + storages: + users.storage: + adapter: 'azureoss' + options: + client: 'azure_blob_storage_client' + container: 'container_name' + prefix: 'optional/path/prefix' +``` + ## AsyncAws S3 ### Installation diff --git a/src/Adapter/AdapterDefinitionFactory.php b/src/Adapter/AdapterDefinitionFactory.php index fc4e6df..6f6d031 100644 --- a/src/Adapter/AdapterDefinitionFactory.php +++ b/src/Adapter/AdapterDefinitionFactory.php @@ -32,6 +32,7 @@ public function __construct() new Builder\AsyncAwsAdapterDefinitionBuilder(), new Builder\AwsAdapterDefinitionBuilder(), new Builder\AzureAdapterDefinitionBuilder(), + new Builder\AzureOssAdapterDefinitionBuilder(), new Builder\FtpAdapterDefinitionBuilder(), new Builder\GcloudAdapterDefinitionBuilder(), new Builder\GridFSAdapterDefinitionBuilder(), diff --git a/src/Adapter/Builder/AzureOssAdapterDefinitionBuilder.php b/src/Adapter/Builder/AzureOssAdapterDefinitionBuilder.php new file mode 100644 index 0000000..635d6cd --- /dev/null +++ b/src/Adapter/Builder/AzureOssAdapterDefinitionBuilder.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace League\FlysystemBundle\Adapter\Builder; + +use AzureOss\FlysystemAzureBlobStorage\AzureBlobStorageAdapter; +use AzureOss\Storage\Blob\BlobContainerClient; +use AzureOss\Storage\Blob\BlobServiceClient; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @author Titouan Galopin + * + * @internal + */ +final class AzureOssAdapterDefinitionBuilder extends AbstractAdapterDefinitionBuilder +{ + public function getName(): string + { + return 'azureoss'; + } + + protected function getRequiredPackages(): array + { + return [ + AzureBlobStorageAdapter::class => 'azure-oss/storage-blob-flysystem', + ]; + } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('client'); + $resolver->setAllowedTypes('client', 'string'); + + $resolver->setRequired('container'); + $resolver->setAllowedTypes('container', 'string'); + + $resolver->setDefault('prefix', ''); + $resolver->setAllowedTypes('prefix', 'string'); + } + + protected function configureDefinition(Definition $definition, array $options, ?string $defaultVisibilityForDirectories): void + { + $containerClient = new Definition(BlobContainerClient::class); + $containerClient->setFactory([self::class, 'initializeBlobContainerClient']); + $containerClient->setArguments([ + new Reference($options['client']), + $options['container'], + ]); + + $definition->setClass(AzureBlobStorageAdapter::class); + $definition->setArgument(0, $containerClient); + $definition->setArgument(1, $options['prefix']); + } + + public static function initializeBlobContainerClient(BlobServiceClient $blobServiceClient, string $container): BlobContainerClient + { + return $blobServiceClient->getContainerClient($container); + } +} diff --git a/tests/Adapter/Builder/AzureOssAdapterDefinitionBuilderTest.php b/tests/Adapter/Builder/AzureOssAdapterDefinitionBuilderTest.php new file mode 100644 index 0000000..01e1b41 --- /dev/null +++ b/tests/Adapter/Builder/AzureOssAdapterDefinitionBuilderTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\League\FlysystemBundle\Adapter\Builder; + +use AzureOss\FlysystemAzureBlobStorage\AzureBlobStorageAdapter; +use League\FlysystemBundle\Adapter\Builder\AzureOssAdapterDefinitionBuilder; +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Definition; + +/** + * @requires PHP 8.1 + */ +class AzureOssAdapterDefinitionBuilderTest extends TestCase +{ + public function createBuilder(): AzureOssAdapterDefinitionBuilder + { + return new AzureOssAdapterDefinitionBuilder(); + } + + public function provideValidOptions(): \Generator + { + yield 'minimal' => [[ + 'client' => 'my_client', + 'container' => 'container_name', + ]]; + + yield 'prefix' => [[ + 'client' => 'my_client', + 'container' => 'container_name', + 'prefix' => 'prefix/path', + ]]; + } + + /** + * @dataProvider provideValidOptions + */ + public function testCreateDefinition($options): void + { + $this->assertSame(AzureBlobStorageAdapter::class, $this->createBuilder()->createDefinition($options, null)->getClass()); + } + + public function testOptionsBehavior(): void + { + $definition = $this->createBuilder()->createDefinition([ + 'client' => 'my_client', + 'container' => 'container_name', + 'prefix' => 'prefix/path', + ], null); + + $this->assertSame(AzureBlobStorageAdapter::class, $definition->getClass()); + $this->assertInstanceOf(Definition::class, $definition->getArgument(0)); + $this->assertSame('prefix/path', $definition->getArgument(1)); + } +}