diff --git a/README.md b/README.md index 2cd1c88..d984930 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ For each storage defined under `flysystem.storages`, an associated service is cr name you provide (in this case, a service `default.storage` will be created). The bundle also creates a named alias for each of these services. -This means you have two way of using the defined storages: +This means you have two ways of using the defined storages: * either using autowiring, by typehinting against the `FilesystemOperator` and using the variable name matching one of your storages: @@ -111,6 +111,7 @@ to interact with your storage. 4. [Using a lazy adapter to switch storage backend using an environment variable](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/4-using-lazy-adapter-to-switch-at-runtime.md) 5. [Creating a custom adapter](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/5-creating-a-custom-adapter.md) 6. [MongoDB GridFS](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/6-gridfs.md) +7. [WebDAV](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/7-webdav.md) * [Security issue disclosure procedure](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/A-security-disclosure-procedure.md) * [Configuration reference](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/B-configuration-reference.md) diff --git a/composer.json b/composer.json index 9169176..880b01b 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "league/flysystem-memory": "^3.1", "league/flysystem-read-only": "^3.15", "league/flysystem-sftp-v3": "^3.1", + "league/flysystem-webdav": "^3.29", "symfony/dotenv": "^5.4 || ^6.0 || ^7.0", "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0", "symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0", diff --git a/docs/7-webdav.md b/docs/7-webdav.md new file mode 100644 index 0000000..66dbc7c --- /dev/null +++ b/docs/7-webdav.md @@ -0,0 +1,34 @@ +# WebDAV + +Flysystem is able to [interact with WebDAV servers](https://flysystem.thephpleague.com/docs/adapter/webdav/). +To configure this bundle for such usage, you can rely on adapters in the same way you would +for other storages. + +### Installation + +``` +composer require league/flysystem-webdav +``` + +### Usage + +```yaml +# config/packages/flysystem.yaml + +services: + webdav_client: + class: Sabre\DAV\Client + arguments: + - { baseUri: 'https://webdav.example.com/', userName: 'your_user', password: 'superSecret1234' } + +flysystem: + storages: + webdav.storage: + adapter: 'webdav' + options: + client: 'webdav_client' + prefix: 'optional/path/prefix' + visibility_handling: !php/const \League\Flysystem\WebDAV\WebDAVAdapter::ON_VISIBILITY_THROW_ERROR # throw + manual_copy: false + manual_move: false +``` diff --git a/src/Adapter/AdapterDefinitionFactory.php b/src/Adapter/AdapterDefinitionFactory.php index 8d366cd..2b20797 100644 --- a/src/Adapter/AdapterDefinitionFactory.php +++ b/src/Adapter/AdapterDefinitionFactory.php @@ -38,6 +38,7 @@ public function __construct() new Builder\LocalAdapterDefinitionBuilder(), new Builder\MemoryAdapterDefinitionBuilder(), new Builder\SftpAdapterDefinitionBuilder(), + new Builder\WebDAVAdapterDefinitionBuilder(), ]; } diff --git a/src/Adapter/Builder/WebDAVAdapterDefinitionBuilder.php b/src/Adapter/Builder/WebDAVAdapterDefinitionBuilder.php new file mode 100644 index 0000000..ec3fcd8 --- /dev/null +++ b/src/Adapter/Builder/WebDAVAdapterDefinitionBuilder.php @@ -0,0 +1,67 @@ + + * + * 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 League\Flysystem\WebDAV\WebDAVAdapter; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @author Kévin Dunglas + * + * @internal + */ +final class WebDAVAdapterDefinitionBuilder extends AbstractAdapterDefinitionBuilder +{ + public function getName(): string + { + return 'webdav'; + } + + protected function getRequiredPackages(): array + { + return [ + WebDAVAdapter::class => 'league/flysystem-webdav', + ]; + } + + protected function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('client'); + $resolver->setAllowedTypes('client', 'string'); + + $resolver->setDefault('prefix', ''); + $resolver->setAllowedTypes('prefix', 'string'); + + $resolver->setDefault('visibility_handling', WebDAVAdapter::ON_VISIBILITY_THROW_ERROR); + $resolver->setAllowedTypes('visibility_handling', ['string']); + + $resolver->setDefault('manual_copy', false); + $resolver->setAllowedTypes('manual_copy', 'bool'); + + $resolver->setDefault('manual_move', false); + $resolver->setAllowedTypes('manual_move', 'bool'); + } + + protected function configureDefinition(Definition $definition, array $options, ?string $defaultVisibilityForDirectories): void + { + $definition->setClass(WebDAVAdapter::class); + $definition->setArguments([ + new Reference($options['client']), + $options['prefix'], + $options['visibility_handling'], + $options['manual_copy'], + $options['manual_move'], + ]); + } +} diff --git a/tests/Adapter/Builder/WebDAVAdapterDefinitionBuilderTest.php b/tests/Adapter/Builder/WebDAVAdapterDefinitionBuilderTest.php new file mode 100644 index 0000000..082ae05 --- /dev/null +++ b/tests/Adapter/Builder/WebDAVAdapterDefinitionBuilderTest.php @@ -0,0 +1,69 @@ + + * + * 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 League\Flysystem\Visibility; +use League\Flysystem\WebDAV\WebDAVAdapter; +use League\FlysystemBundle\Adapter\Builder\WebDAVAdapterDefinitionBuilder; +use PHPUnit\Framework\TestCase; + +/** + * @author Kévin Dunglas + */ +class WebDAVAdapterDefinitionBuilderTest extends TestCase +{ + public function createBuilder(): WebDAVAdapterDefinitionBuilder + { + return new WebDAVAdapterDefinitionBuilder(); + } + + public static function provideValidOptions(): \Generator + { + yield 'minimal' => [[ + 'client' => 'webdav_client', + ]]; + + yield 'full' => [[ + 'client' => 'webdav_client', + 'prefix' => 'optional/path/prefix', + 'visibility_handling' => WebDAVAdapter::ON_VISIBILITY_THROW_ERROR, + 'manual_copy' => false, + 'manual_move' => false, + ]]; + } + + /** + * @dataProvider provideValidOptions + */ + public function testCreateDefinition(array $options): void + { + $this->assertSame(WebDAVAdapter::class, $this->createBuilder()->createDefinition($options, null)->getClass()); + } + + public function testOptionsBehavior(): void + { + $definition = $this->createBuilder()->createDefinition([ + 'client' => 'webdav_client', + 'prefix' => 'optional/path/prefix', + 'visibility_handling' => WebDAVAdapter::ON_VISIBILITY_IGNORE, + 'manual_copy' => false, + 'manual_move' => false, + ], Visibility::PUBLIC); + + $this->assertSame(WebDAVAdapter::class, $definition->getClass()); + $this->assertSame('webdav_client', (string) $definition->getArgument(0)); + $this->assertSame('optional/path/prefix', $definition->getArgument(1)); + $this->assertSame(WebDAVAdapter::ON_VISIBILITY_IGNORE, $definition->getArgument(2)); + $this->assertFalse($definition->getArgument(3)); + $this->assertFalse($definition->getArgument(4)); + } +}