diff --git a/.docheader b/.docheader index 90283e9..67db0b4 100644 --- a/.docheader +++ b/.docheader @@ -5,7 +5,7 @@ file that was distributed with this source code. @see https://bushbaby.nl/ -@copyright Copyright (c) 2014-%year% bushbaby multimedia. (https://bushbaby.nl) +@copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) @author Bas Kamer @license MIT diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db7002c..c3155b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,21 +14,10 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - dependencies: - - "--prefer-lowest" - - "" php-version: + - "8.2" + - "8.1" - "8.0" - - "7.4" - composer: - - "v2" - include: - - php-version: "7.3" - composer: "v1" - dependencies: "--prefer-lowest" - - php-version: "7.3" - composer: "v1" - dependencies: "" steps: - name: "Checkout" @@ -37,9 +26,9 @@ jobs: uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" - tools: "composer:${{ matrix.composer }}" + ini-values: zend.assertions=1,assert.exception=1 - name: "Install dependencies" - run: "composer update ${{ matrix.dependencies }} --no-interaction" + run: "composer update --no-interaction" - name: "Run tests" run: "vendor/bin/phpunit" @@ -54,11 +43,11 @@ jobs: with: php-version: "8.0" tools: "composer:v2" - coverage: "pcov" + ini-values: zend.assertions=1,assert.exception=1 - name: "Install dependencies" run: "composer update --no-interaction" - name: "Install coveralls" - run: "composer require --dev php-coveralls/php-coveralls" + run: "composer require --dev php-coveralls/php-coveralls:^2.0 --with-all-dependencies" - name: "Generate coverage" run: "vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml --configuration ./phpunit.xml.dist" - name: "Publish coverage" diff --git a/.gitignore b/.gitignore index 9155db3..ac4b857 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.php_cs.cache +.php-cs-fixer.cache composer.lock vendor .phpunit.result.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 7bc2788..dab7e72 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -23,8 +23,4 @@ $config->getFinder()->in(__DIR__)->append([__FILE__]); -$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__; - -$config->setCacheFile($cacheDir . '/.php_cs.cache'); - return $config; diff --git a/README.md b/README.md index 791b2ad..f6ccef2 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,7 @@ A simple Laminas module that bridges the Flysystem filesystem. -[![Latest Stable Version](https://poser.pugx.org/bushbaby/flysystem/v/stable)](https://packagist.org/packages/bushbaby/flysystem) -[![Total Downloads](https://poser.pugx.org/bushbaby/flysystem/downloads)](https://packagist.org/packages/bushbaby/flysystem) -[![Latest Unstable Version](https://poser.pugx.org/bushbaby/flysystem/v/unstable)](https://packagist.org/packages/bushbaby/flysystem) -[![License](https://poser.pugx.org/bushbaby/flysystem/license)](https://packagist.org/packages/bushbaby/flysystem) - +[![Latest Stable Version](http://poser.pugx.org/bushbaby/flysystem/v)](https://packagist.org/packages/bushbaby/flysystem) [![Total Downloads](http://poser.pugx.org/bushbaby/flysystem/downloads)](https://packagist.org/packages/bushbaby/flysystem) [![Latest Unstable Version](http://poser.pugx.org/bushbaby/flysystem/v/unstable)](https://packagist.org/packages/bushbaby/flysystem) [![License](http://poser.pugx.org/bushbaby/flysystem/license)](https://packagist.org/packages/bushbaby/flysystem) [![PHP Version Require](http://poser.pugx.org/bushbaby/flysystem/require/php)](https://packagist.org/packages/bushbaby/flysystem) ![Build Status](https://github.com/bushbaby/BsbFlysystem/actions/workflows/test.yml/badge.svg) [![Code Coverage](https://scrutinizer-ci.com/g/bushbaby/BsbFlysystem/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/bushbaby/BsbFlysystem/?branch=master) @@ -22,6 +18,28 @@ Then add `BsbFlysystem` to the `config/application.config.php` modules list. Copy the `config/bsb_flysystem.local.php.dist` to the `config/autoload` directory to jump start configuration. +## Deprecations + +- dropped support for [FlySystem](https://flysystem.thephpleague.com/docs/) v1 and v2 +- dropped support for [EventableFilesystem](https://github.com/thephpleague/flysystem-eventable-filesystem) +- dropped support for [CachedAdapter](https://github.com/thephpleague/flysystem-cached-adapter) +- dropped support for [Laminas Service Manager v2](https://docs.laminas.dev/laminas-servicemanager/migration) +- dropped support for [Null Adapter](https://github.com/thephpleague/flysystem/issues/1303) +- dropped support for [VFS Adapter](https://github.com/thephpleague/flysystem-eventable-filesystem) +- dropped support for [RackSpace Adapter](https://github.com/thephpleague/flysystem-rackspace) +- dropped support for [Plugin System](https://flysystem.thephpleague.com/docs/what-is-new/) + +## Migrating to v8 + +Configuration changes + +- For the adapter configuration the 'type' key has been renamed to 'factory'. Each adapter is now referenced by its FQCN in a 'factory' key. +- The 'options' is now passed to the adapter factory as an named arguments array. Look at individual adapter constructor which opions are available. Some options - such as 'mimeTypeDetector' may be a valid service names. The adapter will pull an instance from the service manager. +- The 'shared' option has been removed. Both the filesystem- and adapter service are plugin managers. Services pulled from a Laminas Plugin Manager with additional creation options are using the build method of the service manager and are thus not shared. +- The 'adapter_map' has been removed. The adapter configuration is now done in the 'adapters' key. The 'adapter_map' was used to overload the default adapter list. This is no longer needed as the default adapter list is now empty. +- And ofcourse look at the api changes from Flysystem [Upgrade from 1.x +](https://flysystem.thephpleague.com/docs/upgrade-from-1.x/) and [new in Flysystem V2 & V3](https://flysystem.thephpleague.com/docs/what-is-new/) + ## Configuration Configuration regarding BsbFlysystem lives in the top-level configuration key `bsb_flysystem`. @@ -30,26 +48,26 @@ The configuration consists of the following base elements; - *Adapters* are consumed by a Filesystem. - *Filesystems* filesystem are consumed in userland. -- *Adapter Map* is used to overload the default adapter list. ### Adapters To configure an adapter you add a key to `bsb_flysystem->adapters` with a associative array containing the following options; -- type \ Type of adapter -- shared \ (optional) Defines the shared option of a [Laminas service](https://docs.laminas.dev/laminas-servicemanager/configuring-the-service-manager/). -- options \ Options specific per adapter (see [flysystem](http://flysystem.thephpleague.com) or config/bsb_flysystem.local.php.dist) +- factory \ The FQCN of a factory used to create an adapter. +- options \ named arguments passed to each adapter constructor (see [flysystem](http://flysystem.thephpleague.com) or peek into config/bsb_flysystem.local.php.dist) +- options.prefix \ (optional) Any filesystem adapter can be scoped down to a prefixed path using [Path Prefixing](https://flysystem.thephpleague.com/docs/adapter/path-prefixing/). +- options.readonly \ (optional) Any filesystem adapter can be made read-only [Read only adapter](https://flysystem.thephpleague.com/docs/adapter/read-only/). - -example: a local adapter pointing to ./data/files +example: a readonly local adapter pointing to ./data/files ``` 'bsb_flysystem' => [ 'adapters' => [ 'local_files' => [ - 'type' => 'local', + 'factory' => BsbFlysystem\Adapter\Factory\LocalAdapterFactory::class, 'options' => [ - 'root' => './data/files' + 'location' => './data/files', + 'readonly' => true, ], ], ], @@ -58,110 +76,25 @@ example: a local adapter pointing to ./data/files ### Filesystems -Configure a filesystems by adding to `bsb_flysystem->filesystems`. Each filesystem may containing the following options; +Configure a filesystem by adding to `bsb_flysystem->filesystems`. Each filesystem may containing the following options; - adapter \ Name of adapter service. -- cache \ (optional) If defined as string it should be a name of a service present in the main service locator. Defaults to false. -- eventable \ When true returns an EventableFilesystem instance. (see [flysystem](http://flysystem.thephpleague.com)). -- plugins \ List of FQCN to the plugin you wish to register for this filesystem - -example: Filesystem called 'files' with the previously defined 'local_files' adapter and the 'listFiles' plugin registered. ``` 'bsb_flysystem' => [ 'filesystems' => [ 'files' => [ 'adapter' => 'local_files', - 'cache' => false, - 'eventable' => false, - 'plugins' => [ - 'League\Flysystem\Plugin\ListFiles', - ], ], ], ], ``` - -### Adapter Map - -By default, BsbFlysystem provides a [list of adapters](src/Service/Factory/AdapterManagerFactory.php#L18-35) that are ready to used. - -If you need to add a custom adapter you are able to by registering it onto the `adapter_map` key. - -example : Add a custom Adapter called 'customAdapter' using an invokable class 'Custom\Adapter' - -``` -'bsb_flysystem' => [ - 'adapters' => [ - 'named_adapter' => [ - 'type' => 'customAdapter', - 'shared' => true, - ] - ], - 'adapter_map' => [ - 'invokables' => [ - 'customAdapter' => 'Custom\Adapter' - ] - ] -]; -``` - -#### Caching - -No cache factories are provided by BsbFlysystem. You should write them yourself and register them in main service manager. You can use these by setting the cache option to the name of the service. - -``` -'bsb_flysystem' => [ - 'filesystems' => [ - 'files' => [ - 'cache' => 'My/Service/Cache', - ], - ], -], -'service_manager' => [ - 'factories' => [ - 'My/Service/Cache' => 'My/Service/CacheFactory' - ] -] -``` - -BsbFilesystem is able to automaticly wrap a Laminas caching service in a in such way that a Flysystem instance is able to consume it. - -This means that BsbFlysystem can work with both flysystem caches (implementing `League\Flysystem\Cached\CacheInterface`) and Laminas caches (implementing `Laminas\Cache\Storage\StorageInterface`). - -example: caching options as are common in a Laminas application - -``` -'bsb_flysystem' => [ - 'filesystems' => [ - 'files' => [ - 'cache' => 'Cache\BsbFlystem\Memory', - ], - ], -], -'caches' => [ - 'Cache\BsbFlystem\Memory' => [ - 'adapter' => [ - 'name' => 'memory', - 'options' => [ - 'ttl' => 300, - ], - ], - ], -], -'service_manager' => [ - 'abstract_factories' => [ - \Laminas\Cache\Service\StorageCacheAbstractServiceFactory::class - ], -], -``` - -Further reading in Laminas [documentation](https://docs.laminas.dev/laminas-cache/storage/adapter/). +It is possible to override options given to the adapter factory via the 'adapter_options' key. This is useful if you want to use the same adapter for multiple filesystems but with different options. Typically you would do that when you manually pull a filesystem or adapter from the a plugin manager. #### AdapterManager -The AdapterManager is automaticly configured, However it is possible to tweak its configuration via `bsb_flysystem->adapter_manager`. +The AdapterManager is automaticly configured, however it is possible to tweak its configuration via `bsb_flysystem->adapter_manager`. In particular the lazy_services configuration key may be useful if you use the Rackspace Adapter. BsbFlysystem loads that adapter 'lazily'. A connection is only established until you actually use the adapter. This done with help from [ProxyManager](https://github.com/Ocramius/ProxyManager). As Laminas also uses this libary we take advantage of the 'lazy_services' configuration that may be available in your application. The Rackspace adapter merges the Laminas lazy_services config key with the adapter_manager lazy_services config allowing control over how the ProxyManager handles it's thing. @@ -184,9 +117,9 @@ In particular the lazy_services configuration key may be useful if you use the R ## Usage -By default BsbFlysystem provides one pre-configured filesystem. This is a local filesystem (uncached) and exposes the data directory of a default Laminas application. +By default BsbFlysystem provides one pre-configured filesystem. This is a local filesystem and exposes the data directory of a default Laminas application. This directory is configured to have 'lazyRootCreation'. -Both the filesystems and adapters are Laminas plugin managers and stored within the global service manager. +Both the filesystem- and adapter services are Laminas Plugin Managers and stored within the global service manager. Aliases are registered for both; BsbFlysystemManager and BsbFlysystemAdapterManager. ### Filesystem Manager @@ -195,11 +128,11 @@ In its simplest form this is how we would retrieve a filesystem. We get the file example: Fetch a 'default' filesystem. In this case a 'local' filesystem with a root of 'data'. ``` -$filesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class)->get('default'); +$filesystem = $serviceLocator->get('BsbFlysystemManager')->get('default'); $contents = $filesystem->read('file.txt'); ``` -If we at some point decide we need to store these files on a different system. Rackspace for example, we simply reconfigure the named filesystem service to use a different named adapter service. No need to change the userland implementation. +If at some point you decide files need to be stored on a different system you simply reconfigure the named filesystem service to use a different adapter service. No need to change the userland implementation. ### Adapter Manager @@ -210,28 +143,22 @@ $adapter = $serviceLocator->get(\BsbFlysystem\Service\AdapterManager::class)- $filesystem = new Filesystem($adapter); $contents = $filesystem->read('file.txt'); ``` - ## Provided Factories I have tried to provide factories (and tests) for each of the adapters that come with the Flysystem. Each come with there own set of required and optional options. I refer to the Flysystem documentation for more information. ### Adapters -- Azure -- Aws3S (v3 only) +- Aws3Sv3 +- AzureBlobStorage - Dropbox - Ftp -- Ftpd -- GoogleCloudDrive +- GoogleCloudStorage +- InMemory - Local - BsbFlysystem is preconfigured with an adapter named 'local_data' to expose the ./data directory of a Laminas application. -- Null -- Rackspace - - the ObjectStore Container must exist before usage - - Won't connect until actual usage by Filesystem (thanks to [ProxyManager](https://github.com/Ocramius/ProxyManager)) and uses the same lazy loading configuration Laminas provides. - Replicate - Sftp -- VFS - WebDAV - ZipArchive @@ -239,7 +166,7 @@ A note about the AwsS3 adapter; There are two versions of the AwsS3 sdk and only ### Filesystems -There is one FilesystemFactory which creates a Filesystem or EventableFilesystem based on the configuration +There is one FilesystemFactory which creates a Filesystem based on the configuration. ## Advanced Usage @@ -249,11 +176,10 @@ A feature of Laminas service managers is the ability to create an instance of a Consider the following configuration; Retrieve multiple configured dropbox filesystems based on stored accessTokens retrieved at runtime. -``` +```php 'adapters' => [ 'dropbox_user' => [ 'type' => 'dropbox', - 'shared' => false, 'options' => [ 'client_identifier' => 'app_id', 'access_token' => 'xxxxx', @@ -268,30 +194,25 @@ Consider the following configuration; Retrieve multiple configured dropbox files ], ``` -``` +```php $accessTokens = [...]; foreach ($accessTokens as $accessToken) { - $adapter = $serviceLocator->get(\BsbFlysystem\Service\AdapterManager::class) - ->get('dropbox_user', [ - 'access_token' => $accessToken - ]); + $adapter = $serviceLocator->get(\BsbFlysystem\Service\AdapterManager::class) + ->get('dropbox_user', ['access_token' => $accessToken]); $filesystem = new Filesystem($adapter); $filesystem->put('TOS.txt', 'hi!'); } ``` - Using the same createOptions feature but now directly from the Filesystem Manager. Notice the adapter_options key which are passed to the Adapter Manager by the FilesystemFactory. -``` +```php $accessTokens = [...]; foreach ($accessTokens as $accessToken) { - $filesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class) - ->get('dropbox_user', [ - 'adapter_options' => [ - 'access_token' => $accessToken - ] - ]); + $filesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class) + ->get('dropbox_user', [ + 'adapter_options' => ['access_token' => $accessToken] + ]); $filesystem = new Filesystem($adapter); $filesystem->put('TOS.txt', 'hi!'); @@ -300,9 +221,9 @@ foreach ($accessTokens as $accessToken) { ### Mount Manager -``` -$sourceFilesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class)->get('default'); // local adapter ./data -$targetFilesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class)->get('archive'); // eg. zip archive +```php +$sourceFilesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class)->get('default'); // local adapter ./data +$targetFilesystem = $serviceLocator->get(\BsbFlysystem\Service\FilesystemManager::class)->get('archive'); // eg. zip archive $manager = new League\Flysystem\MountManager(array( 'source' => $sourceFilesystem, @@ -311,7 +232,7 @@ $manager = new League\Flysystem\MountManager(array( $contents = $manager->listContents('source://some_directory', true); foreach ($contents as $entry) { - $manager->put('target://'.$entry['path'], $manager->read('source://'.$entry['path'])); + $manager->write('target://'.$entry->path(), $manager->read('source://'.$entry->path())); } ``` @@ -321,11 +242,11 @@ foreach ($contents as $entry) { `BsbFlysystem\Filter\File\RenameUpload` can be used to rename or move an uploaded file to a Flysystem filesystem. -This class takes an `filesystem` constructor option which must implement `League\Flysystem\FilesystemInterface`. +This class takes an `filesystem` constructor option which must implement `League\Flysystem\Filesystem`. The `BsbFlysystem\Filter\File\RenameUpload` extends `Laminas\Filter\File\RenameUpload` class so I refer to the Laminas [documentation](https://docs.laminas.dev/laminas-filter/file/#renameupload) for more information. -``` +```php $request = new Request(); $files = $request->getFiles(); // i.e. $files['my-upload']['tmp_name'] === '/tmp/php5Wx0aJ' diff --git a/composer.json b/composer.json index 7a6893c..495ebc1 100644 --- a/composer.json +++ b/composer.json @@ -16,37 +16,52 @@ } ], "require": { - "php": "^7.3 || ^8.0", - "laminas/laminas-stdlib": "^3.0", - "league/flysystem": "^1.0.41", - "psr/container": "^1.0" + "php": "^8.0", + "laminas/laminas-servicemanager": "^3.3", + "league/flysystem": "^3.0", + "psr/container": "^1.0 || ^2.0" }, "require-dev": { + "ajgl/flysystem-replicate": "^2.2", "bushbaby/php-cs-fixer-config": "^2.0", + "friendsofphp/proxy-manager-lts": "^1.0", "laminas/laminas-code": "^3.3.1 || ^4.0.0", "laminas/laminas-config": "^3.1", "laminas/laminas-filter": "^2.9.1", "laminas/laminas-modulemanager": "^2.7.3", "laminas/laminas-mvc": "^3.0", - "laminas/laminas-servicemanager": "^3.3", - "league/flysystem-aws-s3-v3": "~1.0", - "league/flysystem-azure": "~1.0,>=1.0.2", - "league/flysystem-cached-adapter": "~1.0", - "league/flysystem-eventable-filesystem": "~1.0", - "league/flysystem-rackspace": "~1.0", - "league/flysystem-replicate-adapter": "~1.0", - "league/flysystem-sftp": "~1.0", - "league/flysystem-vfs": "^1.0", - "league/flysystem-webdav": "~1.0", - "league/flysystem-ziparchive": "~1.0", - "ocramius/proxy-manager": "~2.0", + "league/flysystem-async-aws-s3": "^3.10", + "league/flysystem-aws-s3-v3": "^3.0", + "league/flysystem-azure-blob-storage": "^3.02", + "league/flysystem-ftp": "^3.10", + "league/flysystem-google-cloud-storage": "^3.11", + "league/flysystem-memory": "^3.10", + "league/flysystem-path-prefixing": "^3.10", + "league/flysystem-read-only": "^3.10", + "league/flysystem-sftp-v3": "^3.0", + "league/flysystem-webdav": "^3.0", + "league/flysystem-ziparchive": "^3.0", + "league/mime-type-detection": "^1.11", + "php-mock/php-mock-phpunit": "^2.6", + "phpspec/prophecy": "^1.16", "phpunit/phpunit": "^9.4.2", - "spatie/flysystem-dropbox": "~1.0", - "superbalist/flysystem-google-storage": "^7.2" + "spatie/flysystem-dropbox": "^2.0" }, "suggest": { - "laminas/laminas-cache": "laminas-cache component ^2.8, if you need laminas-cache support", - "laminas/laminas-filter": "laminas-filter component ^2.9.1, if you need RenameUpload filter" + "laminas/laminas-filter": "laminas-filter component ^2.9.1, if you need RenameUpload filter", + "laminas/laminas-modulemanager": "Use as a Laminas Framework module", + "league/flysystem-path-prefixing": "Use to scope down any filesystem adapter to a prefixed path", + "league/flysystem-read-only": "Turn any Flysystem adapter into a read only adapter", + "league/mime-type-detection": "Supplies generic mime-type detection", + "league/flysystem-ftp": "FTP adapter for use with Flysystem", + "league/flysystem-sftp-v3": "SFTP adapter for use with Flysystem", + "league/flysystem-aws-s3-v3": "Aws S3 adapter for use with Flysystem", + "league/flysystem-async-aws-s3": "Aws Async S3 adapter for use with Flysystem", + "league/flysystem-azure-blob-storage": "Azure Blob Storage adapter for use with Flysystem", + "league/flysystem-google-cloud-storage": "Google Cloud Storage adapter for use with Flysystem", + "league/flysystem-webdav": "Webdav adapter for use with Flysystem", + "league/flysystem-memory": "In memory adapter for use with Flysystem", + "ajgl/flysystem-replicate": "Replicate adapter for use with Flysystem" }, "autoload": { "psr-4": { @@ -60,18 +75,12 @@ }, "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "8.0.x-dev" }, "laminas": { "component": "BsbFlysystem", "config-provider": "BsbFlysystem\\ConfigProvider" - }, - "merge-plugin": { - "include": [ - "composer.php8.json" - ], - "replace": true - } + } }, "config": { "sort-packages": true diff --git a/composer.php8.json b/composer.php8.json deleted file mode 100644 index 4d3f529..0000000 --- a/composer.php8.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "replace": { - "laminas/laminas-cache-storage-adapter-apc": "*", - "laminas/laminas-cache-storage-adapter-dba": "*", - "laminas/laminas-cache-storage-adapter-memcached": "*", - "laminas/laminas-cache-storage-adapter-mongodb": "*", - "laminas/laminas-cache-storage-adapter-wincache": "*", - "laminas/laminas-cache-storage-adapter-xcache": "*", - "laminas/laminas-cache-storage-adapter-zend-server": "*" - } -} diff --git a/config/bsb_flysystem.local.php.dist b/config/bsb_flysystem.local.php.dist index 6f95ae3..dde2a9d 100644 --- a/config/bsb_flysystem.local.php.dist +++ b/config/bsb_flysystem.local.php.dist @@ -1,95 +1,219 @@ [ 'adapters' => [ - 'local_files' => [ - 'type' => 'local', + 'local_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\LocalAdapterFactory::class, + 'options' => [ + 'location' => './test/_build/files', + // 'visibility' => 'service_manager_key', + // 'writeFlags' => LOCK_EX, + // 'linkHandling' => self::DISALLOW_LINKS, + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'lazyRootCreation' => false, + ], + ], + 'ftp_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\FtpAdapterFactory::class, 'options' => [ - 'root' => './data/files' + 'connectionOptions' => [ + 'host' => 'localhost', + 'root' => '/var/www/html', + 'username' => 'username', + 'password' => '', + // 'port' => 21, + // 'ssl' => false, + // 'timeout' => 90, + // 'utf8' => false, + // 'passive' => true, + // 'transferMode' => FtpConnectionOptions::FTP_BINARY, + // 'systemType' => null, + // 'ignorePassiveAddress' => null, + // 'enableTimestampsOnUnixListings' => false, + // 'recurseManually' => false, + // 'useRawListOptions' => null, + ], + // 'connectionProvider' => 'a-connection-provider', + // 'connectivityChecker' => 'a-connectivity-checker', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibilityProvider' => 'service_manager_key', ], ], - 'sftp_default' => [ - 'type' => 'sftp', + 'sftp_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\SftpAdapterFactory::class, 'options' => [ - 'host' => 'xxxxx.xxx', - 'port' => 21, - 'username' => 'xxxxx', - 'password' => 'xxxxx', - // 'privateKey' => 'path/to/or/contents/of/privatekey', - // 'root' => '/path/to/root', - // 'timeout' => 10, + 'connectionProvider' => [ + 'host' => 'xxxxx', + 'username' => 'xxxxx', + // 'password' => 'xxxxx', + // 'privateKey' => null, + // 'passphrase' => null, + // 'port' => 22, + // 'useAgent' => false, + // 'timeout' => 10, + // 'maxTries' => 4, + // 'hostFingerprint' => null, + // 'connectivityChecker' => 'a-connectivity-checker', + // 'preferredAlgorithms' => [], + ], + 'root' => '/var/www/html', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibilityConverter' => 'service_manager_key', ], ], - 'zip_default' => [ - 'type' => 'zip', + 'inmemory_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\InMemoryAdapterFactory::class, 'options' => [ - 'archive' => './data/files.zip', - 'prefix' => '/' + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'defaultVisibility' => \League\Flysystem\Visibility::PUBLIC, ], ], - 'rackspace_default' => [ - 'type' => 'rackspace', + 'azureblobstorage_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\AzureBlobStorageAdapterFactory::class, 'options' => [ - 'url' => "http://api-uri", - 'secret' => [ - 'username' => "xxxxx", - 'password' => "xxxxx", + 'client' => [ + // @see https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + 'connectionString' => 'DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx', + // @see MicrosoftAzure\Storage\Blob\BlobRestProxy::createBlobService + 'options' => [], ], - 'objectstore' => [ - 'name' => 'xxxxx', - 'region' => 'XX', - 'url_type' => 'publicURL', - 'container' => 'xxxxx' + 'container' => 'xxxxx', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'maxResultsForContentsListing' => 5000, + // 'visibilityHandling' => AzureBlobStorageAdapter::ON_VISIBILITY_THROW_ERROR, + // @see MicrosoftAzure\Storage\Common\Internal\StorageServiceSettings + // 'serviceSettings' => [ + // 'name' => 'xxx', + // 'key' => 'xxx', + // 'blobEndpointUri' => 'xxx', + // 'queueEndpointUri' => 'xxx', + // 'tableEndpointUri' => 'xxx', + // 'fileEndpointUri' => 'xxx', + // 'blobSecondaryEndpointUri' => null, + // 'queueSecondaryEndpointUri' => null, + // 'tableSecondaryEndpointUri' => null, + // 'fileSecondaryEndpointUri' => null, + // 'sas' => null, + // ] + ], + ], + 'googlecloudstorage_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\GoogleCloudStorageAdapterFactory::class, + 'options' => [ + 'bucket' => 'service_manager_key', // return a \Google\Cloud\Storage\Bucket + // 'prefix' => '', + // 'visibilityHandler' => 'service_manager_key', // return a \League\Flysystem\Visibility + // 'defaultVisibility' => Visibility::PRIVATE + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + ], + ], + 'zip_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\ZipArchiveAdapterFactory::class, + 'options' => [ + 'zipArchiveProvider' => [ + 'filename' => './test/_build/files.zip', ], - 'prefix' => '/' + 'root' => './test/_build/files', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibility' => 'service_manager_key', ], ], - 'dropbox_default' => [ - 'type' => 'dropbox', + 'dropbox_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\DropboxAdapterFactory::class, 'options' => [ - 'access_token' => 'xxxxx', - 'prefix' => '/' + 'client' => [ // or 'client' => 'service_manager_key' return a \Spatie\Dropbox\Client, + 'accessTokenOrAppCredentials' => 'xxxxx', + // 'client' => null // ClientInterface + // 'maxChunkSize' => \Spatie\Dropbox\Client::MAX_CHUNK_SIZE, + // 'maxUploadChunkRetries' => 0, + // 'teamMemberId' => null + ], + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector ], ], - 'awss3v3_default' => [ - 'type' => 'awss3v3', - 'options' => [ - 'endpoint' => 'http://minio:9000', // optional: Override endpoint: when using another s3 compatible host, remove line if not using - 'use_path_style_endpoint' => false, - 'credentials' => [ - 'key' => 'your-app-id', - 'secret' => 'xxxxx', + 'awss3v3_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\AwsS3v3AdapterFactory::class, + 'options' => [ + 'client' => [ + 'credentials' => [ + 'key' => 'your-app-id', + 'secret' => 'xxxxx', + ], + 'region' => 'eu-west-1', + 'bucket' => 'xxxxx', + 'version' => 'latest', // default: 'latest' + // guzzle request options; see http://docs.guzzlephp.org/en/latest/request-options.html#proxy + 'http' => [ + // 'timeout' => 10, + ], + 'use_path_style_endpoint' => true, // default: false ], - 'region' => 'us-east-1', - 'bucket' => 'xxxxx', - 'version' => 'latest|version', // default: 'latest' - 'request.options' => [], // Guzzle request options; see http://docs.guzzlephp.org/en/latest/request-options.html#proxy + 'bucket' => 'xxxxx', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'defaultVisibility' => \League\Flysystem\Visibility::PUBLIC, + // 'options' => [], + // 'streamReads' => true, + // 'forwardedOptions' => self::AVAILABLE_OPTIONS, + // 'metadataFields' => self::EXTRA_METADATA_FIELDS, + // 'multipartUploadOptions' => self::MUP_AVAILABLE_OPTIONS, ], ], - 'webdav_default' => [ - 'type' => 'webdav', + 'replicate_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\ReplicateAdapterFactory::class, 'options' => [ - 'baseUri' => 'http://demo.sabredav.org/', - 'userName' => 'testuser', - 'password' => 'test' + 'source' => 'local_default', + 'replica' => 'zip_default', ], ], - 'azure_default' => [ - 'type' => 'azure', + 'webdav_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\WebDAVAdapterFactory::class, 'options' => [ - 'container' => 'your-container', - 'account-name' => 'xxxxx', - 'account-key' => 'xxxxx' + 'client' => [ + 'baseUri' => 'https://example.org/remote.php/webdav/', + // 'userName' => '', + // 'password' => '', + // 'proxy' => '', + // 'authType' => '', + // 'encoding' => '', + ], + // 'prefix' => '', + // 'visibilityHandling' => WebDAVAdapter::ON_VISIBILITY_THROW_ERROR, + // 'manualCopy' => false, + // 'manualMove' => false, ], - ] + ], ], 'filesystems' => [ - 'files' => [ - 'adapter' => 'xxxx', - 'cache' => false, - 'eventable' => false, + 'default' => [ + 'adapter' => 'local_default', + 'adapter_options' => null, + 'options' => [ + 'pathNormalizer' => null, // returns PathNormalizer::class + 'publicUrlGenerator' => null, // returns \League\Flysystem\UrlGeneration\PublicUrlGeneratorInterface::class + 'temporaryUrlGenerator' => null, // returns \League\Flysystem\UrlGeneration\TemporaryUrlGenerator::class + ], ], ], + 'adapter_manager' => [ + 'config' => [], + 'lazy_services' => [ + // directory where proxy classes will be written - default to system_get_tmp_dir() + // 'proxies_target_dir' => 'data/cache', + // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy" + // 'proxies_namespace' => null, + // whether the generated proxy classes should be written to disk + // 'write_proxy_files' => false, + ], + ], + 'filesystem_manager' => [ + 'config' => [], + ], ], ]; diff --git a/config/module.config.php b/config/module.config.php deleted file mode 100644 index 920d5ef..0000000 --- a/config/module.config.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -use BsbFlysystem\Service\AdapterManager; -use BsbFlysystem\Service\Factory\AdapterManagerFactory; -use BsbFlysystem\Service\Factory\FilesystemManagerFactory; -use BsbFlysystem\Service\FilesystemManager; - -return [ - 'bsb_flysystem' => [ - 'adapters' => [ - 'local_data' => [ - 'type' => 'local', - 'options' => [ - 'root' => './data', - ], - ], - ], - 'cache' => [ - 'default' => [ - 'type' => 'adapter', - 'file' => 'file.cache', - 'ttl' => 300, - ], - ], - 'filesystems' => [ - 'default' => [ - 'adapter' => 'local_data', - ], - ], - 'adapter_manager' => [ - 'config' => [], - 'lazy_services' => [ - // directory where proxy classes will be written - default to system_get_tmp_dir() - // 'proxies_target_dir' => 'data/cache', - // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy" - // 'proxies_namespace' => null, - // whether the generated proxy classes should be written to disk - // 'write_proxy_files' => false, - ], - ], - 'filesystem_manager' => [ - 'config' => [], - ], - ], - 'service_manager' => [ - 'aliases' => [ - 'BsbFlysystemManager' => FilesystemManager::class, - 'BsbFlysystemAdapterManager' => AdapterManager::class, - ], - 'factories' => [ - AdapterManager::class => AdapterManagerFactory::class, - FilesystemManager::class => FilesystemManagerFactory::class, - ], - ], -]; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1690e6b..d255932 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,21 +1,18 @@ - - - - - test - - - - - - ./src - - - - - - - - + + + + ./src + + + + + + + + + test + + + diff --git a/src/Adapter/Factory/AbstractAdapterFactory.php b/src/Adapter/Factory/AbstractAdapterFactory.php index 1071e60..2a20708 100644 --- a/src/Adapter/Factory/AbstractAdapterFactory.php +++ b/src/Adapter/Factory/AbstractAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,9 +19,10 @@ namespace BsbFlysystem\Adapter\Factory; -use InvalidArgumentException; use Laminas\Stdlib\ArrayUtils; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\PathPrefixing\PathPrefixedAdapter; +use League\Flysystem\ReadOnly\ReadOnlyFilesystemAdapter; use ProxyManager\Configuration; use ProxyManager\Factory\LazyLoadingValueHolderFactory; use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; @@ -34,9 +35,6 @@ abstract class AbstractAdapterFactory */ protected $options; - /** - * AbstractAdapterFactory constructor. - */ public function __construct(array $options = []) { $this->setCreationOptions($options); @@ -44,13 +42,31 @@ public function __construct(array $options = []) /** * Set creation options. + * + * @codeCoverageIgnore */ public function setCreationOptions(array $options): void { $this->options = $options; + + if (\array_key_exists('prefix', $this->options)) { + \assert( + \is_string($this->options['prefix']) && ! empty(trim($this->options['prefix'], '/')), + "Option 'prefix' must be a non empty string and may not be enclosed with a '/'" + ); + + $this->options['prefix'] = trim($this->options['prefix'], '/'); + } + + if (\array_key_exists('readonly', $this->options)) { + \assert( + \is_bool($this->options['readonly']), + "Option 'readonly' must be a boolean" + ); + } } - public function __invoke(ContainerInterface $container, $requestedName, array $options = null): AdapterInterface + public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): FilesystemAdapter { if (null !== $options) { $this->setCreationOptions($options); @@ -60,18 +76,32 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $this->validateConfig(); - $service = $this->doCreateService($container); + // support path prefixing + $prefix = class_exists(PathPrefixedAdapter::class) && ($this->options['prefix'] ?? false); + if ($prefix) { + $prefix = $this->options['prefix']; - return $service; - } + // prefix may still be an adapter option even without PathPrefixedAdapter class for some adapters + unset($this->options['prefix']); + } - public function createService(ContainerInterface $container): AdapterInterface - { - if (method_exists($container, 'getServiceLocator')) { - $container = $container->getServiceLocator(); + // support read only + $readonly = class_exists(ReadOnlyFilesystemAdapter::class) && ($this->options['readonly'] ?? false); + + // never pass readonly as adapter option + unset($this->options['readonly']); + + $adapter = $this->doCreateService($container); + + if ($prefix) { + $adapter = new PathPrefixedAdapter($adapter, $prefix); + } + + if ($readonly) { + $adapter = new ReadOnlyFilesystemAdapter($adapter); } - return $this($container, func_get_arg(2)); + return $adapter; } /** @@ -94,7 +124,9 @@ protected function mergeMvcConfig(ContainerInterface $container, string $request } /** - * @throws InvalidArgumentException + * @throws \InvalidArgumentException + * + * @codeCoverageIgnore */ public function getLazyFactory(ContainerInterface $container): LazyLoadingValueHolderFactory { @@ -106,7 +138,7 @@ public function getLazyFactory(ContainerInterface $container): LazyLoadingValueH ); if (! isset($config['lazy_services'])) { - throw new InvalidArgumentException('Missing "lazy_services" config key'); + throw new \InvalidArgumentException('Missing "lazy_services" config key'); } $lazyServices = $config['lazy_services']; @@ -133,7 +165,7 @@ public function getLazyFactory(ContainerInterface $container): LazyLoadingValueH /** * Create service. */ - abstract protected function doCreateService(ContainerInterface $container): AdapterInterface; + abstract protected function doCreateService(ContainerInterface $container): FilesystemAdapter; /** * Implement in adapter. diff --git a/src/Adapter/Factory/AwsS3v3AdapterFactory.php b/src/Adapter/Factory/AwsS3v3AdapterFactory.php index 4bb3c0e..90a0aa7 100644 --- a/src/Adapter/Factory/AwsS3v3AdapterFactory.php +++ b/src/Adapter/Factory/AwsS3v3AdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -21,86 +21,58 @@ use Aws\S3\S3Client; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\AwsS3v3\AwsS3Adapter as Adapter; +use League\Flysystem\AwsS3V3\AwsS3V3Adapter; +use League\Flysystem\FilesystemAdapter; use Psr\Container\ContainerInterface; class AwsS3v3AdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { + if (! class_exists(AwsS3V3Adapter::class)) { throw new RequirementsException(['league/flysystem-aws-s3-v3'], 'AwsS3v3'); } - $config = [ - 'region' => $this->options['region'], - 'version' => $this->options['version'], - 'http' => $this->options['request.options'], - ]; - // Override the endpoint for example: when using an s3 compatible host - if (! empty($this->options['endpoint'])) { - $config['endpoint'] = $this->options['endpoint']; - } - - if (! empty($this->options['use_path_style_endpoint'])) { - $config['use_path_style_endpoint'] = $this->options['use_path_style_endpoint']; - } + $clientConfig = $this->options['client']; if (! isset($this->options['iam']) || (isset($this->options['iam']) && (false === $this->options['iam']))) { $credentials = [ - 'key' => $this->options['credentials']['key'], - 'secret' => $this->options['credentials']['secret'], + 'key' => $this->options['client']['credentials']['key'], + 'secret' => $this->options['client']['credentials']['secret'], ]; - $config = array_merge(compact('credentials'), $config); - } - - $adapterOptions = $this->options['options'] ?? []; - - $client = new S3Client($config); - - return new Adapter($client, $this->options['bucket'], $this->options['prefix'], $adapterOptions, $this->options['streamReads']); - } - - protected function validateConfig(): void - { - if (! isset($this->options['iam']) || (isset($this->options['iam']) && (false === $this->options['iam']))) { - if (! isset($this->options['credentials']) || ! \is_array($this->options['credentials'])) { - throw new UnexpectedValueException("Missing 'credentials' as array"); - } - - if (! isset($this->options['credentials']['key'])) { - throw new UnexpectedValueException("Missing 'key' as option"); - } - - if (! isset($this->options['credentials']['secret'])) { - throw new UnexpectedValueException("Missing 'secret' as option"); - } + $clientConfig = array_merge(compact('credentials'), $clientConfig); } - if (! isset($this->options['region'])) { - throw new UnexpectedValueException("Missing 'region' as option"); - } - - if (! isset($this->options['bucket'])) { - throw new UnexpectedValueException("Missing 'bucket' as option"); - } + $this->options['client'] = new S3Client($clientConfig); - if (! isset($this->options['version'])) { - $this->options['version'] = 'latest'; + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); } - if (! isset($this->options['prefix'])) { - $this->options['prefix'] = ''; + if (\array_key_exists('visibility', $this->options)) { + $this->options['visibility'] = $container->get($this->options['visibility']); } - if (! isset($this->options['request.options'])) { - $this->options['request.options'] = []; - } + return new AwsS3V3Adapter(...$this->options); + } - if (! isset($this->options['streamReads'])) { - $this->options['streamReads'] = true; - } + /** + * @codeCoverageIgnore + */ + protected function validateConfig(): void + { + // if (! isset($this->options['iam']) || (isset($this->options['iam']) && (false === $this->options['iam']))) { + // if (! isset($this->options['credentials']) || ! \is_array($this->options['credentials'])) { + // throw new UnexpectedValueException("Missing 'credentials' as array"); + // } + + // if (! isset($this->options['credentials']['key'])) { + // throw new UnexpectedValueException("Missing 'key' as option"); + // } + + // if (! isset($this->options['credentials']['secret'])) { + // throw new UnexpectedValueException("Missing 'secret' as option"); + // } + // } } } diff --git a/src/Adapter/Factory/AzureAdapterFactory.php b/src/Adapter/Factory/AzureAdapterFactory.php deleted file mode 100755 index daf2732..0000000 --- a/src/Adapter/Factory/AzureAdapterFactory.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Adapter\Factory; - -use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Azure\AzureAdapter as Adapter; -use MicrosoftAzure\Storage\Common\ServicesBuilder; -use Psr\Container\ContainerInterface; - -class AzureAdapterFactory extends AbstractAdapterFactory -{ - public function doCreateService(ContainerInterface $container): AdapterInterface - { - if (! class_exists(Adapter::class)) { - throw new RequirementsException(['league/flysystem-azure'], 'Azure'); - } - $endpoint = sprintf( - 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s', - $this->options['account-name'], - $this->options['account-key'] - ); - - $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($endpoint); - - return new Adapter($blobRestProxy, $this->options['container']); - } - - protected function validateConfig(): void - { - if (! isset($this->options['account-name'])) { - throw new UnexpectedValueException("Missing 'account-name' as option"); - } - - if (! isset($this->options['account-key'])) { - throw new UnexpectedValueException("Missing 'account-key' as option"); - } - - if (! isset($this->options['container'])) { - throw new UnexpectedValueException("Missing 'container' as option"); - } - } -} diff --git a/src/Adapter/Factory/AzureBlobStorageAdapterFactory.php b/src/Adapter/Factory/AzureBlobStorageAdapterFactory.php new file mode 100755 index 0000000..eb546ef --- /dev/null +++ b/src/Adapter/Factory/AzureBlobStorageAdapterFactory.php @@ -0,0 +1,208 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystem\Adapter\Factory; + +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\AzureBlobStorage\AzureBlobStorageAdapter; +use League\Flysystem\FilesystemAdapter; +use MicrosoftAzure\Storage\Blob\BlobRestProxy; +use MicrosoftAzure\Storage\Common\Internal\StorageServiceSettings; +use Psr\Container\ContainerInterface; + +class AzureBlobStorageAdapterFactory extends AbstractAdapterFactory +{ + public function doCreateService(ContainerInterface $container): FilesystemAdapter + { + if (! class_exists(AzureBlobStorageAdapter::class)) { + throw new RequirementsException(['league/flysystem-azure'], 'Azure'); + } + + if (\is_string($this->options['client'])) { + $this->options['client'] = $container->get($this->options['client']); + } else { + $this->options['client'] = BlobRestProxy::createBlobService(...$this->options['client']); + } + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + if (isset($this->options['serviceSettings'])) { + $this->options['serviceSettings'] = new StorageServiceSettings(...$this->options['serviceSettings']); + } + + return new AzureBlobStorageAdapter(...$this->options); + } + + /** + * @codeCoverageIgnore + */ + protected function validateConfig(): void + { + \assert( + \array_key_exists('client', $this->options), + "Required option 'client' is missing" + ); + + \assert( + (\is_string($this->options['client']) && ! empty($this->options['client'])) + || \is_array($this->options['client']), + "Option 'client' must either be a non empty string or an array" + ); + + if (\is_array($this->options['client'])) { + \assert( + \array_key_exists('connectionString', $this->options['client']), + "Required option 'client.connectionString' is missing" + ); + + \assert( + \is_string($this->options['client']['connectionString']) && (! empty($this->options['client']['connectionString'])) + || \is_array($this->options['client']['connectionString']), + "Option 'client.connectionString' must either be a non empty string or an array" + ); + + if (\array_key_exists('options', $this->options['client'])) { + \assert( + \is_array($this->options['client']['options']), + "Option 'client.options' must be an array" + ); + } + } + + \assert( + \array_key_exists('container', $this->options), + "Required option 'container' is missing" + ); + + \assert( + \is_string($this->options['container']) && ! empty($this->options['container']), + "Option 'container' must be a non empty string" + ); + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); + } + + if (\array_key_exists('prefix', $this->options)) { + \assert( + \is_string($this->options['prefix']), + "Option 'prefix' must be a string" + ); + } + + if (\array_key_exists('maxResultsForContentsListing', $this->options)) { + \assert( + \is_int($this->options['maxResultsForContentsListing']), + "Option 'maxResultsForContentsListing' must be an integer" + ); + } + + if (\array_key_exists('visibilityHandling', $this->options)) { + \assert( + \is_string($this->options['visibilityHandling']), + "Option 'visibilityHandling' must be a string" + ); + + \assert( + \in_array($this->options['visibilityHandling'], [AzureBlobStorageAdapter::ON_VISIBILITY_THROW_ERROR, AzureBlobStorageAdapter::ON_VISIBILITY_IGNORE], true), + sprintf("Option 'visibilityHandling' must either be '%s' or '%s'", AzureBlobStorageAdapter::ON_VISIBILITY_THROW_ERROR, AzureBlobStorageAdapter::ON_VISIBILITY_IGNORE) + ); + } + + if (\array_key_exists('serviceSettings', $this->options)) { + \assert( + \is_array($this->options['serviceSettings']), + "Option 'serviceSettings' must be an array" + ); + + \assert( + \array_key_exists('name', $this->options['serviceSettings']), + "Required option 'serviceSettings.name' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['name']) && ! empty($this->options['serviceSettings']['name']), + "Option 'serviceSettings.name' must be a non empty string" + ); + + \assert( + \array_key_exists('key', $this->options['serviceSettings']), + "Required option 'serviceSettings.key' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['key']) && ! empty($this->options['serviceSettings']['key']), + "Option 'serviceSettings.key' must be a non empty string" + ); + + \assert( + \array_key_exists('blobEndpointUri', $this->options['serviceSettings']), + "Required option 'serviceSettings.blobEndpointUri' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['blobEndpointUri']) && ! empty($this->options['serviceSettings']['blobEndpointUri']), + "Option 'serviceSettings.blobEndpointUri' must be a non empty string" + ); + + \assert( + \array_key_exists('queueEndpointUri', $this->options['serviceSettings']), + "Required option 'serviceSettings.queueEndpointUri' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['queueEndpointUri']) && ! empty($this->options['serviceSettings']['queueEndpointUri']), + "Option 'serviceSettings.queueEndpointUri' must be a non empty string" + ); + \assert( + \array_key_exists('queueEndpointUri', $this->options['serviceSettings']), + "Required option 'serviceSettings.queueEndpointUri' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['queueEndpointUri']) && ! empty($this->options['serviceSettings']['queueEndpointUri']), + "Option 'serviceSettings.queueEndpointUri' must be a non empty string" + ); + \assert( + \array_key_exists('tableEndpointUri', $this->options['serviceSettings']), + "Required option 'serviceSettings.tableEndpointUri' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['tableEndpointUri']) && ! empty($this->options['serviceSettings']['tableEndpointUri']), + "Option 'serviceSettings.tableEndpointUri' must be a non empty string" + ); + + \assert( + \array_key_exists('fileEndpointUri', $this->options['serviceSettings']), + "Required option 'serviceSettings.fileEndpointUri' is missing" + ); + + \assert( + \is_string($this->options['serviceSettings']['fileEndpointUri']) && ! empty($this->options['serviceSettings']['fileEndpointUri']), + "Option 'serviceSettings.fileEndpointUri' must be a non empty string" + ); + } + } +} diff --git a/src/Adapter/Factory/DropboxAdapterFactory.php b/src/Adapter/Factory/DropboxAdapterFactory.php index 80ef237..300fd9f 100644 --- a/src/Adapter/Factory/DropboxAdapterFactory.php +++ b/src/Adapter/Factory/DropboxAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,35 +20,75 @@ namespace BsbFlysystem\Adapter\Factory; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; use Psr\Container\ContainerInterface; use Spatie\Dropbox\Client; -use Spatie\FlysystemDropbox\DropboxAdapter as Adapter; +use Spatie\Dropbox\TokenProvider; +use Spatie\FlysystemDropbox\DropboxAdapter; class DropboxAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { + if (! class_exists(DropboxAdapter::class)) { throw new RequirementsException(['spatie/flysystem-dropbox'], 'Dropbox'); } - $client = new Client( - $this->options['access_token'] - ); + if (\is_string($this->options['client'])) { + $this->options['client'] = $container->get($this->options['client']); + } else { + $this->options['client'] = new Client(...$this->options['client']); + } - return new Adapter($client, $this->options['prefix']); + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + return new DropboxAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['access_token'])) { - throw new UnexpectedValueException("Missing 'access_token' as option"); + \assert( + \array_key_exists('client', $this->options), + "Required option 'client' is missing" + ); + + \assert( + (\is_string($this->options['client']) && ! empty($this->options['client'])) + || \is_array($this->options['client']), + "Option 'client' must either be a non empty string or an array" + ); + + if (\is_array($this->options['client'])) { + \assert( + \array_key_exists('accessTokenOrAppCredentials', $this->options['client']), + "Required option 'client.accessTokenOrAppCredentials' is missing" + ); + + \assert( + (\is_string($this->options['client']['accessTokenOrAppCredentials']) && ! empty($this->options['client']['accessTokenOrAppCredentials'])) + || \is_array($this->options['client']['accessTokenOrAppCredentials']) + || $this->options['client']['accessTokenOrAppCredentials'] instanceof TokenProvider, + "Option 'client.accessTokenOrAppCredentials' must either be a non empty string, an array or an instance of 'Spatie\Dropbox\TokenProvider'" + ); + + if (\is_array($this->options['client']['accessTokenOrAppCredentials'])) { + \assert( + 2 === \count($this->options['client']['accessTokenOrAppCredentials']), + "Option 'client.accessTokenOrAppCredentials' must be an array with 2 elements" + ); + } } - if (! isset($this->options['prefix'])) { - $this->options['prefix'] = ''; + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); } } } diff --git a/src/Adapter/Factory/FtpAdapterFactory.php b/src/Adapter/Factory/FtpAdapterFactory.php index 17f0cc8..83bd627 100644 --- a/src/Adapter/Factory/FtpAdapterFactory.php +++ b/src/Adapter/Factory/FtpAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,34 +19,122 @@ namespace BsbFlysystem\Adapter\Factory; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\Adapter\Ftp as Adapter; -use League\Flysystem\AdapterInterface; +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\Ftp\FtpAdapter; +use League\Flysystem\Ftp\FtpConnectionOptions; use Psr\Container\ContainerInterface; class FtpAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - return new Adapter($this->options); + if (! class_exists(FtpAdapter::class)) { + throw new RequirementsException(['league/flysystem-ftp'], 'Ftp'); + } + + $this->options['connectionOptions'] = new FtpConnectionOptions(...$this->options['connectionOptions']); + + if (\array_key_exists('connectionProvider', $this->options)) { + $this->options['connectionProvider'] = $container->get($this->options['connectionProvider']); + } + + if (\array_key_exists('connectivityChecker', $this->options)) { + $this->options['connectivityChecker'] = $container->get($this->options['connectivityChecker']); + } + + if (\array_key_exists('visibilityConverter', $this->options)) { + $this->options['visibilityConverter'] = $container->get($this->options['visibilityConverter']); + } + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + return new FtpAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['host'])) { - throw new UnexpectedValueException("Missing 'host' as option"); + \assert( + \array_key_exists('connectionOptions', $this->options), + "Required option 'connectionOptions' is missing" + ); + + \assert( + \is_array($this->options['connectionOptions']), + "Option 'connectionOptions' must be an array" + ); + + \assert( + \array_key_exists('host', $this->options['connectionOptions']), + "Required option 'connectionOptions.host' is missing" + ); + + \assert( + \is_string($this->options['connectionOptions']['host']) && ! empty($this->options['connectionOptions']['host']), + "Option 'connectionOptions.host' must be a non empty string" + ); + + \assert( + \array_key_exists('root', $this->options['connectionOptions']), + "Required option 'connectionOptions.root' is missing" + ); + + \assert( + \is_string($this->options['connectionOptions']['root']) && ! empty($this->options['connectionOptions']['root']), + "Option 'connectionOptions.root' must be a non empty string" + ); + + \assert( + \array_key_exists('username', $this->options['connectionOptions']), + "Required option 'connectionOptions.username' is missing" + ); + + \assert( + \is_string($this->options['connectionOptions']['username']) && ! empty($this->options['connectionOptions']['username']), + "Option 'connectionOptions.username' must be a non empty string" + ); + + \assert( + \array_key_exists('password', $this->options['connectionOptions']), + "Required option 'connectionOptions.password' is missing" + ); + + \assert( + \is_string($this->options['connectionOptions']['password']), + "Option 'connectionOptions.password' must be a string" + ); + + if (\array_key_exists('connectionProvider', $this->options)) { + \assert( + \is_string($this->options['connectionProvider']) && ! empty($this->options['connectionProvider']), + "Option 'connectionProvider' must be a non empty string" + ); } - if (! isset($this->options['port'])) { - throw new UnexpectedValueException("Missing 'port' as option"); + if (\array_key_exists('connectivityChecker', $this->options)) { + \assert( + \is_string($this->options['connectivityChecker']) && ! empty($this->options['connectivityChecker']), + "Option 'connectivityChecker' must be a non empty string" + ); } - if (! isset($this->options['username'])) { - throw new UnexpectedValueException("Missing 'username' as option"); + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); } - if (! isset($this->options['password'])) { - throw new UnexpectedValueException("Missing 'password' as option"); + if (\array_key_exists('visibilityConverter', $this->options)) { + \assert( + \is_string($this->options['visibilityConverter']) && ! empty($this->options['visibilityConverter']), + "Option 'visibilityConverter' must be a non empty string" + ); } } } diff --git a/src/Adapter/Factory/FtpdAdapterFactory.php b/src/Adapter/Factory/FtpdAdapterFactory.php deleted file mode 100644 index 61cd71a..0000000 --- a/src/Adapter/Factory/FtpdAdapterFactory.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Adapter\Factory; - -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\Adapter\Ftpd as Adapter; -use League\Flysystem\AdapterInterface; -use Psr\Container\ContainerInterface; - -class FtpdAdapterFactory extends AbstractAdapterFactory -{ - public function doCreateService(ContainerInterface $container): AdapterInterface - { - return new Adapter($this->options); - } - - protected function validateConfig(): void - { - if (! isset($this->options['host'])) { - throw new UnexpectedValueException("Missing 'host' as option"); - } - - if (! isset($this->options['port'])) { - throw new UnexpectedValueException("Missing 'port' as option"); - } - - if (! isset($this->options['username'])) { - throw new UnexpectedValueException("Missing 'username' as option"); - } - - if (! isset($this->options['password'])) { - throw new UnexpectedValueException("Missing 'password' as option"); - } - } -} diff --git a/src/Adapter/Factory/GoogleCloudDriveAdapterFactory.php b/src/Adapter/Factory/GoogleCloudDriveAdapterFactory.php deleted file mode 100644 index 6ea0c0e..0000000 --- a/src/Adapter/Factory/GoogleCloudDriveAdapterFactory.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Adapter\Factory; - -use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use Google\Cloud\Storage\StorageClient; -use League\Flysystem\AdapterInterface; -use Psr\Container\ContainerInterface; -use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter as Adapter; - -class GoogleCloudDriveAdapterFactory extends AbstractAdapterFactory -{ - public function doCreateService(ContainerInterface $container): AdapterInterface - { - if (! class_exists(Adapter::class)) { - throw new RequirementsException(['superbalist/flysystem-google-storage'], 'GoogleCloudDrive'); - } - - $storageClient = new StorageClient([ - 'projectId' => $this->options['project_id'], - ]); - - $bucket = $storageClient->bucket($this->options['bucket']); - - return new Adapter($storageClient, $bucket); - } - - protected function validateConfig(): void - { - if (! isset($this->options['project_id'])) { - throw new UnexpectedValueException("Missing 'project_id' as option"); - } - - if (! isset($this->options['bucket'])) { - throw new UnexpectedValueException("Missing 'bucket' as option"); - } - } -} diff --git a/src/Adapter/Factory/GoogleCloudStorageAdapterFactory.php b/src/Adapter/Factory/GoogleCloudStorageAdapterFactory.php new file mode 100644 index 0000000..aba5cba --- /dev/null +++ b/src/Adapter/Factory/GoogleCloudStorageAdapterFactory.php @@ -0,0 +1,89 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystem\Adapter\Factory; + +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\GoogleCloudStorage\GoogleCloudStorageAdapter; +use League\Flysystem\Visibility; +use Psr\Container\ContainerInterface; + +class GoogleCloudStorageAdapterFactory extends AbstractAdapterFactory +{ + public function doCreateService(ContainerInterface $container): FilesystemAdapter + { + if (! class_exists(GoogleCloudStorageAdapter::class)) { + throw new RequirementsException(['league/flysystem-google-cloud-storage'], 'GoogleCloudDrive'); + } + + $this->options['bucket'] = $container->get($this->options['bucket']); + + if (isset($this->options['visibilityHandler'])) { + $this->options['visibilityHandler'] = $container->get($this->options['visibilityHandler']); + } + + if (isset($this->options['mimeTypeDetector'])) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + return new GoogleCloudStorageAdapter(...$this->options); + } + + /** + * @codeCoverageIgnore + */ + protected function validateConfig(): void + { + \assert( + \array_key_exists('bucket', $this->options), + "Required option 'bucket' is missing" + ); + + \assert( + \is_string($this->options['bucket']) && ! empty($this->options['bucket']), + "Option 'bucket' must be a non empty string" + ); + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); + } + + if (\array_key_exists('defaultVisibility', $this->options)) { + \assert( + \is_string($this->options['defaultVisibility']) && ! empty($this->options['defaultVisibility']), + "Option 'defaultVisibility' must be a non empty string" + ); + \assert( + \in_array($this->options['defaultVisibility'], [Visibility::PUBLIC, Visibility::PRIVATE], true), + sprintf("Option 'defaultVisibility' must either be '%s' or '%s'", Visibility::PUBLIC, Visibility::PRIVATE) + ); + } + + if (\array_key_exists('visibilityHandler', $this->options)) { + \assert( + \is_string($this->options['visibilityHandler']) && ! empty($this->options['visibilityHandler']), + "Option 'visibilityHandler' must be a non empty string" + ); + } + } +} diff --git a/src/Adapter/Factory/InMemoryAdapterFactory.php b/src/Adapter/Factory/InMemoryAdapterFactory.php new file mode 100644 index 0000000..cbce0c3 --- /dev/null +++ b/src/Adapter/Factory/InMemoryAdapterFactory.php @@ -0,0 +1,66 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystem\Adapter\Factory; + +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; +use League\Flysystem\Visibility; +use Psr\Container\ContainerInterface; + +class InMemoryAdapterFactory extends AbstractAdapterFactory +{ + public function doCreateService(ContainerInterface $container): FilesystemAdapter + { + if (! class_exists(InMemoryFilesystemAdapter::class)) { + throw new RequirementsException(['league/flysystem-memory'], 'InMemory'); + } + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + return new InMemoryFilesystemAdapter(...$this->options); + } + + /** + * @codeCoverageIgnore + */ + protected function validateConfig(): void + { + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); + } + + if (\array_key_exists('defaultVisibility', $this->options)) { + \assert( + \is_string($this->options['defaultVisibility']) && ! empty($this->options['defaultVisibility']), + "Option 'defaultVisibility' must be a non empty string" + ); + \assert( + \in_array($this->options['defaultVisibility'], [Visibility::PUBLIC, Visibility::PRIVATE], true), + sprintf("Option 'defaultVisibility' must either be '%s' or '%s'", Visibility::PUBLIC, Visibility::PRIVATE) + ); + } + } +} diff --git a/src/Adapter/Factory/LocalAdapterFactory.php b/src/Adapter/Factory/LocalAdapterFactory.php index f3c36b1..f239493 100644 --- a/src/Adapter/Factory/LocalAdapterFactory.php +++ b/src/Adapter/Factory/LocalAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,34 +19,73 @@ namespace BsbFlysystem\Adapter\Factory; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\Adapter\Local as Adapter; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\Local\LocalFilesystemAdapter; use Psr\Container\ContainerInterface; class LocalAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - $options = []; - $options[] = $this->options['root']; - $options[] = $this->options['writeFlags'] ?? null; - - if (isset($this->options['linkHandling'])) { // since 1.0.8 - $options[] = $this->options['linkHandling']; + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } - if (isset($this->options['permissions'])) { // since 1.0.14 - $options[] = $this->options['permissions']; - } + if (\array_key_exists('visibility', $this->options)) { + $this->options['visibility'] = $container->get($this->options['visibility']); } - return new Adapter(...$options); + return new LocalFilesystemAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['root'])) { - throw new UnexpectedValueException("Missing 'root' as option"); + \assert( + \array_key_exists('location', $this->options), + "Required option 'location' is missing" + ); + + \assert( + \is_string($this->options['location']), + "Option 'location' must be a string" + ); + + if (\array_key_exists('visibility', $this->options)) { + \assert( + \is_string($this->options['visibility']) && ! empty($this->options['visibility']), + "Option 'visibility' must be a non empty string" + ); + } + + if (\array_key_exists('writeFlags', $this->options)) { + \assert( + \is_int($this->options['writeFlags']), + "Option 'visibility' must be an integer" + ); + } + + if (\array_key_exists('linkHandling', $this->options)) { + \assert( + \is_int($this->options['LinkHandling']), + "Option 'LinkHandling' must be an integer" + ); + } + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); + } + + if (\array_key_exists('lazyRootCreation', $this->options)) { + \assert( + \is_bool($this->options['lazyRootCreation']), + "Option 'lazyRootCreation' must be a boolean" + ); } } } diff --git a/src/Adapter/Factory/RackspaceAdapterFactory.php b/src/Adapter/Factory/RackspaceAdapterFactory.php deleted file mode 100644 index ef16985..0000000 --- a/src/Adapter/Factory/RackspaceAdapterFactory.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Adapter\Factory; - -use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Rackspace\RackspaceAdapter as Adapter; -use OpenCloud\OpenStack; -use ProxyManager\Factory\LazyLoadingValueHolderFactory; -use Psr\Container\ContainerInterface; - -class RackspaceAdapterFactory extends AbstractAdapterFactory -{ - public function doCreateService(ContainerInterface $container): AdapterInterface - { - if (! class_exists(Adapter::class) || - ! class_exists(LazyLoadingValueHolderFactory::class) - ) { - throw new RequirementsException(['league/flysystem-rackspace', 'ocramius/proxy-manager'], 'Rackspace'); - } - - /** @var AdapterInterface $proxy */ - $proxy = $this->getLazyFactory($container)->createProxy( - Adapter::class, - function (&$wrappedObject, $proxy, $method, $parameters, &$initializer) { - $client = new OpenStack( - $this->options['url'], - $this->options['secret'], - $this->options['options'] - ); - - $store = $client->objectStoreService( - $this->options['objectstore']['name'], - $this->options['objectstore']['region'], - $this->options['objectstore']['url_type'] - ); - - $container = $store->getContainer($this->options['objectstore']['container']); - - $wrappedObject = new Adapter($container, $this->options['prefix']); - - return true; - } - ); - - return $proxy; - } - - protected function validateConfig(): void - { - if (! isset($this->options['url'])) { - throw new UnexpectedValueException("Missing 'url' as option"); - } - - if (! isset($this->options['secret']) || ! \is_array($this->options['secret'])) { - throw new UnexpectedValueException("Missing 'secret' as option"); - } - - if (! isset($this->options['objectstore']) || ! \is_array($this->options['objectstore'])) { - throw new UnexpectedValueException("Missing 'objectstore' as option"); - } elseif (! isset($this->options['objectstore']['name'])) { - throw new UnexpectedValueException("Missing 'objectstore.name' as option"); - } elseif (! isset($this->options['objectstore']['region'])) { - throw new UnexpectedValueException("Missing 'objectstore.region' as option"); - } elseif (! isset($this->options['objectstore']['container'])) { - throw new UnexpectedValueException("Missing 'objectstore.container' as option"); - } - - if (! isset($this->options['objectstore']['url_type'])) { - $this->options['objectstore']['url_type'] = null; - } - - if (! isset($this->options['options'])) { - $this->options['options'] = []; - } - - if (! isset($this->options['prefix'])) { - $this->options['prefix'] = null; - } - } -} diff --git a/src/Adapter/Factory/ReplicateAdapterFactory.php b/src/Adapter/Factory/ReplicateAdapterFactory.php index 1e9f8f3..83df551 100644 --- a/src/Adapter/Factory/ReplicateAdapterFactory.php +++ b/src/Adapter/Factory/ReplicateAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,36 +19,51 @@ namespace BsbFlysystem\Adapter\Factory; +use Ajgl\Flysystem\Replicate\ReplicateFilesystemAdapter; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Replicate\ReplicateAdapter as Adapter; +use BsbFlysystem\Service\AdapterManager; +use League\Flysystem\FilesystemAdapter; use Psr\Container\ContainerInterface; class ReplicateAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { - throw new RequirementsException(['league/flysystem-replicate-adapter'], 'Replicate'); + if (! class_exists(ReplicateFilesystemAdapter::class)) { + throw new RequirementsException(['ajgl/flysystem-replicate'], 'Replicate'); } - $connectionManager = $container->get('BsbFlysystemAdapterManager'); + $manager = $container->get(AdapterManager::class); - return new Adapter( - $connectionManager->get($this->options['source']), - $connectionManager->get($this->options['replicate']) + return new ReplicateFilesystemAdapter( + $manager->get($this->options['source']), + $manager->get($this->options['replica']) ); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['source'])) { - throw new UnexpectedValueException("Missing 'source' as option"); - } + \assert( + \array_key_exists('source', $this->options), + "Required option 'source' is missing" + ); - if (! isset($this->options['replicate'])) { - throw new UnexpectedValueException("Missing 'replicate' as option"); - } + \assert( + \is_string($this->options['source']) && ! empty($this->options['source']), + "Option 'source' must be a non empty string" + ); + + \assert( + \array_key_exists('replica', $this->options), + "Required option 'replica' is missing" + ); + + \assert( + \is_string($this->options['replica']) && ! empty($this->options['replica']), + "Option 'replica' must be a non empty string" + ); } } diff --git a/src/Adapter/Factory/SftpAdapterFactory.php b/src/Adapter/Factory/SftpAdapterFactory.php index cba684e..87245cf 100644 --- a/src/Adapter/Factory/SftpAdapterFactory.php +++ b/src/Adapter/Factory/SftpAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,38 +20,100 @@ namespace BsbFlysystem\Adapter\Factory; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Sftp\SftpAdapter as Adapter; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\PhpseclibV3\SftpAdapter; +use League\Flysystem\PhpseclibV3\SftpConnectionProvider; use Psr\Container\ContainerInterface; class SftpAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { + if (! class_exists(SftpAdapter::class)) { throw new RequirementsException(['league/flysystem-sftp'], 'Sftp'); } - return new Adapter($this->options); + if (\array_key_exists('connectivityChecker', $this->options['connectionProvider'])) { + $this->options['connectionProvider']['connectivityChecker'] = $container->get($this->options['connectionProvider']['connectivityChecker']); + } + + $this->options['connectionProvider'] = new SftpConnectionProvider(...$this->options['connectionProvider']); + + if (\array_key_exists('visibilityConverter', $this->options)) { + $this->options['visibilityConverter'] = $container->get($this->options['visibilityConverter']); + } + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + return new SftpAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['host'])) { - throw new UnexpectedValueException("Missing 'host' as option"); - } + \assert( + \array_key_exists('connectionProvider', $this->options), + "Required option 'connectionProvider' is missing" + ); + + \assert( + \is_array($this->options['connectionProvider']), + "Option 'connectionProvider' must be an array" + ); + + \assert( + \array_key_exists('host', $this->options['connectionProvider']), + "Required option 'connectionProvider.host' is missing" + ); + + \assert( + \is_string($this->options['connectionProvider']['host']) && ! empty($this->options['connectionProvider']['host']), + "Option 'connectionProvider.host' must be a non empty string" + ); + + \assert( + \array_key_exists('username', $this->options['connectionProvider']), + "Required option 'connectionProvider.username' is missing" + ); + + \assert( + \is_string($this->options['connectionProvider']['username']) && ! empty($this->options['connectionProvider']['username']), + "Option 'connectionProvider.username' must be a non empty string" + ); + + \assert( + \array_key_exists('root', $this->options), + "Required option 'root' is missing" + ); + + \assert( + \is_string($this->options['root']) && ! empty($this->options['root']), + "Option 'root' must be a non empty string" + ); - if (! isset($this->options['port'])) { - throw new UnexpectedValueException("Missing 'port' as option"); + if (\array_key_exists('connectivityChecker', $this->options['connectionProvider'])) { + \assert( + \is_string($this->options['connectionProvider']['connectivityChecker']) && ! empty($this->options['connectionProvider']['connectivityChecker']), + "Option 'connectionProvider.connectivityChecker' must be a non empty string" + ); } - if (! isset($this->options['username'])) { - throw new UnexpectedValueException("Missing 'username' as option"); + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); } - if (! isset($this->options['password']) && ! isset($this->options['privateKey'])) { - throw new UnexpectedValueException("Missing either 'password' or 'privateKey' as option"); + if (\array_key_exists('visibilityConverter', $this->options)) { + \assert( + \is_string($this->options['visibilityConverter']) && ! empty($this->options['visibilityConverter']), + "Option 'visibilityConverter' must be a non empty string" + ); } } } diff --git a/src/Adapter/Factory/VfsAdapterFactory.php b/src/Adapter/Factory/VfsAdapterFactory.php deleted file mode 100644 index aef0de4..0000000 --- a/src/Adapter/Factory/VfsAdapterFactory.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Adapter\Factory; - -use BsbFlysystem\Exception\RequirementsException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\Vfs\VfsAdapter as Adapter; -use Psr\Container\ContainerInterface; -use VirtualFileSystem\FileSystem as Vfs; - -class VfsAdapterFactory extends AbstractAdapterFactory -{ - public function doCreateService(ContainerInterface $container): AdapterInterface - { - if (! class_exists(Adapter::class)) { - throw new RequirementsException(['league/flysystem-vfs'], 'Vfs'); - } - - return new Adapter(new Vfs()); - } - - /** - * This adapter has no options. - */ - protected function validateConfig(): void - { - } -} diff --git a/src/Adapter/Factory/WebDAVAdapterFactory.php b/src/Adapter/Factory/WebDAVAdapterFactory.php index 233d570..8f540b3 100644 --- a/src/Adapter/Factory/WebDAVAdapterFactory.php +++ b/src/Adapter/Factory/WebDAVAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,34 +19,110 @@ namespace BsbFlysystem\Adapter\Factory; +use Assert\Assertion; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\WebDAV\WebDAVAdapter as Adapter; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\WebDAV\WebDAVAdapter; use Psr\Container\ContainerInterface; use Sabre\DAV\Client; class WebDAVAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { + if (! class_exists(WebDAVAdapter::class)) { throw new RequirementsException(['league/flysystem-webdav'], 'WebDAV'); } - $client = new Client($this->options); + $this->options['client'] = new Client($this->options['client']); - return new Adapter($client, $this->options['prefix']); + return new WebDAVAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['baseUri'])) { - throw new UnexpectedValueException("Missing 'baseUri' as option"); + \assert( + \array_key_exists('client', $this->options), + "Required option 'client' is missing" + ); + + \assert( + \is_array($this->options['client']), + "Option 'client' must be an array" + ); + + \assert( + \array_key_exists('baseUri', $this->options['client']), + "Required option 'client.baseUri' is missing" + ); + + \assert( + \is_string($this->options['client']['baseUri']) && ! empty($this->options['client']['baseUri']), + "Option 'client.baseUri' must be a non empty string" + ); + + if (isset($this->options['client']['userName'])) { + \assert( + \is_string($this->options['client']['userName']) && ! empty($this->options['client']['userName']), + "Option 'client.userName' must be a non empty string" + ); + } + + if (isset($this->options['client']['password'])) { + \assert( + \is_string($this->options['client']['password']) && ! empty($this->options['client']['password']), + "Option 'client.password' must be a non empty string" + ); + } + + if (isset($this->options['client']['proxy'])) { + \assert( + \is_string($this->options['client']['proxy']), + "Option 'client.proxy' must be a string" + ); + } + if (isset($this->options['client']['encoding'])) { + \assert( + \is_string($this->options['client']['encoding']), + "Option 'client.encoding' must be a string" + ); + } + + if (isset($this->options['client']['authType'])) { + \assert( + \is_int($this->options['client']['authType']), + "Option 'client.authType' must be an integer" + ); + } + + if (isset($this->options['prefix'])) { + \assert( + \is_string($this->options['prefix']) && ! empty($this->options['prefix']), + "Option 'prefix' must be a non empty string" + ); + } + + if (isset($this->options['visibilityHandling'])) { + \assert( + \is_string($this->options['visibilityHandling']), + "Option 'visibilityHandling' must be a string" + ); + + \assert( + \in_array($this->options['visibilityHandling'], [WebDAVAdapter::ON_VISIBILITY_THROW_ERROR, WebDAVAdapter::ON_VISIBILITY_IGNORE], true), + sprintf("Option 'visibilityHandling' must either be '%s' or '%s'", WebDAVAdapter::ON_VISIBILITY_THROW_ERROR, WebDAVAdapter::ON_VISIBILITY_IGNORE) + ); + } + + if (isset($this->options['manualCopy'])) { + Assertion::boolean($this->options['manualCopy'], sprintf("Option '%s' must be a boolean", 'manualCopy')); } - if (! isset($this->options['prefix'])) { - $this->options['prefix'] = null; + if (isset($this->options['manualMove'])) { + Assertion::boolean($this->options['manualMove'], sprintf("Option '%s' must be a boolean", 'manualMove')); } } } diff --git a/src/Adapter/Factory/ZipArchiveAdapterFactory.php b/src/Adapter/Factory/ZipArchiveAdapterFactory.php index 45751ff..78c6bb6 100644 --- a/src/Adapter/Factory/ZipArchiveAdapterFactory.php +++ b/src/Adapter/Factory/ZipArchiveAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,30 +20,86 @@ namespace BsbFlysystem\Adapter\Factory; use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use League\Flysystem\AdapterInterface; -use League\Flysystem\ZipArchive\ZipArchiveAdapter as Adapter; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\ZipArchive\FilesystemZipArchiveProvider; +use League\Flysystem\ZipArchive\ZipArchiveAdapter; use Psr\Container\ContainerInterface; class ZipArchiveAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { - if (! class_exists(Adapter::class)) { - throw new RequirementsException(['league/ziparchive'], 'ZipArchive'); + if (! class_exists(ZipArchiveAdapter::class)) { + throw new RequirementsException(['league/flysystem-ziparchive'], 'ZipArchive'); } - return new Adapter($this->options['archive'], null, $this->options['prefix']); + $this->options['zipArchiveProvider'] = new FilesystemZipArchiveProvider(...$this->options['zipArchiveProvider']); + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + $this->options['mimeTypeDetector'] = $container->get($this->options['mimeTypeDetector']); + } + + if (\array_key_exists('visibility', $this->options)) { + $this->options['visibility'] = $container->get($this->options['visibility']); + } + + return new ZipArchiveAdapter(...$this->options); } + /** + * @codeCoverageIgnore + */ protected function validateConfig(): void { - if (! isset($this->options['archive'])) { - throw new UnexpectedValueException("Missing 'archive' as option"); + \assert( + \array_key_exists('zipArchiveProvider', $this->options), + "Required option 'zipArchiveProvider' is missing" + ); + + \assert( + \is_array($this->options['zipArchiveProvider']), + "Option 'zipArchiveProvider' must be an array" + ); + + \assert( + \array_key_exists('filename', $this->options['zipArchiveProvider']), + "Required option 'zipArchiveProvider.filename' is missing" + ); + + \assert( + \is_string($this->options['zipArchiveProvider']['filename']), + "Option 'zipArchiveProvider.filename' must be a string" + ); + + if (\array_key_exists('localDirectoryPermissions', $this->options['zipArchiveProvider'])) { + \assert( + \is_int($this->options['zipArchiveProvider']['localDirectoryPermissions']), + "Option 'zipArchiveProvider.localDirectoryPermissions' must be an integer" + ); + } + + \assert( + \array_key_exists('root', $this->options), + "Required option 'root' is missing" + ); + + \assert( + \is_string($this->options['root']), + "Option 'root' must be a string" + ); + + if (\array_key_exists('mimeTypeDetector', $this->options)) { + \assert( + \is_string($this->options['mimeTypeDetector']) && ! empty($this->options['mimeTypeDetector']), + "Option 'mimeTypeDetector' must be a non empty string" + ); } - if (! isset($this->options['prefix'])) { - $this->options['prefix'] = null; + if (\array_key_exists('visibility', $this->options)) { + \assert( + \is_string($this->options['visibility']) && ! empty($this->options['visibility']), + "Option 'visibility' must be a non empty string" + ); } } } diff --git a/src/Cache/ZendStorageCache.php b/src/Cache/ZendStorageCache.php deleted file mode 100644 index b25a95c..0000000 --- a/src/Cache/ZendStorageCache.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystem\Cache; - -use Laminas\Cache\Storage\StorageInterface; -use League\Flysystem\Cached\Storage\AbstractCache; - -/** - * Wrapper class that allows usage of a Zend Cache as a Flysystem Cache. - */ -class ZendStorageCache extends AbstractCache -{ - /** - * @var string storage key - */ - protected $key; - - /** - * @var StorageInterface - */ - protected $storage; - - public function __construct(StorageInterface $storage, string $key = 'bsbflysystem') - { - $this->storage = $storage; - $this->key = $key; - } - - public function load(): void - { - $contents = $this->storage->getItem($this->key); - - if (null !== $contents) { - $this->setFromStorage($contents); - } - } - - public function save(): void - { - $contents = $this->getForStorage(); - $this->storage->setItem($this->key, $contents); - } -} diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index a552705..a519027 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,15 +19,82 @@ namespace BsbFlysystem; -class ConfigProvider +use BsbFlysystem\Adapter\Factory\LocalAdapterFactory; +use BsbFlysystem\Service\AdapterManager; +use BsbFlysystem\Service\Factory\AdapterManagerFactory; +use BsbFlysystem\Service\Factory\FilesystemManagerFactory; +use BsbFlysystem\Service\FilesystemManager; + +final class ConfigProvider { public function __invoke(): array { - $config = (new Module())->getConfig(); + return [ + 'dependencies' => $this->getDependencyConfig(), + 'bsb_flysystem' => [ + 'adapters' => $this->getAdapterConfig(), + 'filesystems' => $this->getFilesystemsConfig(), + 'adapter_manager' => $this->getAdapterManagerConfig(), + 'filesystem_manager' => $this->getFilesystemManagerConfig(), + ], + ]; + } + public function getDependencyConfig(): array + { + return [ + 'aliases' => [ + 'BsbFlysystemManager' => FilesystemManager::class, + 'BsbFlysystemAdapterManager' => AdapterManager::class, + ], + 'factories' => [ + AdapterManager::class => AdapterManagerFactory::class, + FilesystemManager::class => FilesystemManagerFactory::class, + ], + ]; + } + + public function getAdapterConfig(): array + { + return [ + 'local_data' => [ + 'factory' => LocalAdapterFactory::class, + 'options' => [ + 'location' => './data', + 'lazyRootCreation' => true, + ], + ], + ]; + } + + public function getFilesystemsConfig(): array + { + return [ + 'default' => [ + 'adapter' => 'local_data', + ], + ]; + } + + public function getAdapterManagerConfig(): array + { + return [ + 'config' => [], + 'lazy_services' => [ + // directory where proxy classes will be written - default to system_get_tmp_dir() + // 'proxies_target_dir' => 'data/cache', + // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy" + // 'proxies_namespace' => null, + // whether the generated proxy classes should be written to disk + // 'write_proxy_files' => false, + ], + ]; + } + + public function getFilesystemManagerConfig(): array + { return [ - 'dependencies' => $config['service_manager'], - 'bsb_flysystem' => $config['bsb_flysystem'], + 'config' => [], ]; } } diff --git a/src/Exception/RequirementsException.php b/src/Exception/RequirementsException.php index 1ee20c6..5c54b5a 100644 --- a/src/Exception/RequirementsException.php +++ b/src/Exception/RequirementsException.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,11 +19,9 @@ namespace BsbFlysystem\Exception; -use Exception; - class RequirementsException extends RuntimeException { - public function __construct(array $requirements, string $for, int $code = 0, Exception $previous = null) + public function __construct(array $requirements, string $for, int $code = 0, \Exception $previous = null) { $requirements = array_map(function ($r) { return sprintf("'%s'", trim($r)); diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index df367f7..2eb15c9 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * diff --git a/src/Exception/UnexpectedValueException.php b/src/Exception/UnexpectedValueException.php index 85f52a1..7b5a1bc 100644 --- a/src/Exception/UnexpectedValueException.php +++ b/src/Exception/UnexpectedValueException.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * diff --git a/src/Filesystem/Factory/FilesystemFactory.php b/src/Filesystem/Factory/FilesystemFactory.php index dd4a7ee..8c88e43 100644 --- a/src/Filesystem/Factory/FilesystemFactory.php +++ b/src/Filesystem/Factory/FilesystemFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,15 +19,8 @@ namespace BsbFlysystem\Filesystem\Factory; -use BsbFlysystem\Cache\ZendStorageCache; -use BsbFlysystem\Exception\RequirementsException; -use BsbFlysystem\Exception\UnexpectedValueException; -use Laminas\Cache\Storage\StorageInterface; -use League\Flysystem\Cached\CachedAdapter; -use League\Flysystem\Cached\CacheInterface; -use League\Flysystem\EventableFilesystem\EventableFilesystem; +use BsbFlysystem\Service\AdapterManager; use League\Flysystem\Filesystem; -use League\Flysystem\FilesystemInterface; use Psr\Container\ContainerInterface; class FilesystemFactory @@ -46,75 +39,40 @@ public function setCreationOptions(array $options): void { $this->options = $options; - if (! isset($this->options['adapter_options'])) { - $this->options['adapter_options'] = []; + if (\array_key_exists('adapter_options', $this->options)) { + \assert( + \is_array($this->options['adapter_options']), + "Option 'adapter_options' must be an array" + ); } } - public function createService(ContainerInterface $container): FilesystemInterface + public function __invoke(ContainerInterface $container, string $requestedName, ?array $options = null): Filesystem { - if (method_exists($container, 'getServiceLocator')) { - $serviceLocator = $container->getServiceLocator(); - } + $filesystems = ($container->has('config') ? $container->get('config') : [])['bsb_flysystem']['filesystems'] ?? []; - $requestedName = func_get_arg(2); + \assert( + \array_key_exists($requestedName, $filesystems) && \is_array($filesystems[$requestedName]), + sprintf("Missing or incorrect configuration for '%s'", $requestedName) + ); - return $this($container, $requestedName); - } + $configForRequestedFS = $filesystems[$requestedName]; - public function __invoke(ContainerInterface $container, $requestedName, array $options = null): FilesystemInterface - { - $config = $container->get('config'); - $fsConfig = $config['bsb_flysystem']['filesystems'][$requestedName]; - if (! isset($fsConfig['adapter'])) { - throw new UnexpectedValueException(sprintf("Missing 'adapter' key for the filesystem '%s' configuration", $requestedName)); - } + \assert( + \array_key_exists('adapter', $configForRequestedFS) && \is_string($configForRequestedFS['adapter']), + sprintf("Missing or incorrect configuration for the 'config.bsb_flysystem.filesystems.%s.adapter'", $requestedName) + ); if (null !== $options) { $this->setCreationOptions($options); } $adapter = $container - ->get('BsbFlysystemAdapterManager') - ->get($fsConfig['adapter'], $this->options['adapter_options']); - - $options = $fsConfig['options'] ?? []; - - if (isset($fsConfig['cache']) && \is_string($fsConfig['cache'])) { - if (! class_exists(CachedAdapter::class)) { - throw new RequirementsException(['league/flysystem-cached-adapter'], 'CachedAdapter'); - } - - $cacheAdapter = $container->get($fsConfig['cache']); + ->get(AdapterManager::class) + ->get($configForRequestedFS['adapter'], $this->options['adapter_options'] ?? null); - // wrap if StorageInterface, use filesystem name a key - if ($cacheAdapter instanceof StorageInterface) { - $cacheAdapter = new ZendStorageCache($cacheAdapter, $requestedName); - } - - // ignore if not CacheInterface - if ($cacheAdapter instanceof CacheInterface) { - $adapter = new CachedAdapter($adapter, $cacheAdapter); - } - } - - if (isset($fsConfig['eventable']) && filter_var($fsConfig['eventable'], FILTER_VALIDATE_BOOLEAN)) { - if (! class_exists(EventableFilesystem::class)) { - throw new RequirementsException(['league/flysystem-eventable-filesystem'], 'EventableFilesystem'); - } - - $filesystem = new EventableFilesystem($adapter, $options); - } else { - $filesystem = new Filesystem($adapter, $options); - } - - if (isset($fsConfig['plugins']) && \is_array($fsConfig['plugins'])) { - foreach ($fsConfig['plugins'] as $plugin) { - $plugin = new $plugin(); - $filesystem->addPlugin($plugin); - } - } + $options = $configForRequestedFS['options'] ?? []; - return $filesystem; + return new Filesystem($adapter, $options); } } diff --git a/src/Filter/File/RenameUpload.php b/src/Filter/File/RenameUpload.php index ff8e6a8..e6d9b44 100644 --- a/src/Filter/File/RenameUpload.php +++ b/src/Filter/File/RenameUpload.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -21,29 +21,29 @@ use Laminas\Filter\Exception; use Laminas\Filter\File\RenameUpload as RenameUploadFilter; -use League\Flysystem\FilesystemInterface; -use UnexpectedValueException; +use League\Flysystem\Filesystem; +use League\Flysystem\FilesystemException; class RenameUpload extends RenameUploadFilter { /** - * @var FilesystemInterface + * @var Filesystem */ protected $filesystem; /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ - public function getFilesystem(): FilesystemInterface + public function getFilesystem(): Filesystem { if (! $this->filesystem) { - throw new UnexpectedValueException('Missing required filesystem.'); + throw new \UnexpectedValueException('Missing required filesystem.'); } return $this->filesystem; } - public function setFilesystem(FilesystemInterface $filesystem): void + public function setFilesystem(Filesystem $filesystem): void { $this->filesystem = $filesystem; } @@ -63,16 +63,19 @@ protected function checkFileExists($targetFile): void protected function moveUploadedFile($sourceFile, $targetFile): bool { if (! is_uploaded_file($sourceFile)) { - throw new Exception\RuntimeException(sprintf("File '%s' could not be uploaded. Filter can move only uploaded files.", $sourceFile), 0); + throw new Exception\RuntimeException(sprintf("File '%s' could not be uploaded. Filter can move only uploaded files.", $sourceFile)); } + $stream = fopen($sourceFile, 'r+'); - $result = $this->getFilesystem()->putStream($targetFile, $stream); - fclose($stream); - if (! $result) { - throw new Exception\RuntimeException(sprintf("File '%s' could not be uploaded. An error occurred while processing the file.", $sourceFile), 0); + try { + $this->getFilesystem()->writeStream($targetFile, $stream); + } catch (FilesystemException $e) { + throw new Exception\RuntimeException(sprintf("File '%s' could not be uploaded. An error occurred while processing the file.", $sourceFile)); + } finally { + fclose($stream); } - return $result; + return true; } } diff --git a/src/Module.php b/src/Module.php index d5d22ee..4eeb0c2 100644 --- a/src/Module.php +++ b/src/Module.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,10 +19,22 @@ namespace BsbFlysystem; -class Module +use Laminas\ModuleManager\Feature\ConfigProviderInterface; + +final class Module implements ConfigProviderInterface { public function getConfig(): array { - return include __DIR__ . '/../config/module.config.php'; + $provider = new ConfigProvider(); + + return [ + 'service_manager' => $provider->getDependencyConfig(), + 'bsb_flysystem' => [ + 'adapters' => $provider->getAdapterConfig(), + 'filesystems' => $provider->getFilesystemsConfig(), + 'adapter_manager' => $provider->getAdapterManagerConfig(), + 'filesystem_manager' => $provider->getFilesystemManagerConfig(), + ], + ]; } } diff --git a/src/Service/AdapterManager.php b/src/Service/AdapterManager.php index fea197e..98bacd1 100644 --- a/src/Service/AdapterManager.php +++ b/src/Service/AdapterManager.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,34 +22,20 @@ use BsbFlysystem\Exception\RuntimeException; use Laminas\ServiceManager\AbstractPluginManager; use Laminas\ServiceManager\Exception; -use Laminas\ServiceManager\Factory\InvokableFactory; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; class AdapterManager extends AbstractPluginManager { /** * @var string */ - protected $instanceOf = AdapterInterface::class; + protected $instanceOf = FilesystemAdapter::class; /** * @var bool */ protected $shareByDefault = true; - /** - * @var bool - */ - protected $sharedByDefault = true; - - /** - * @var array - */ - protected $factories = [ - \League\Flysystem\Adapter\NullAdapter::class => InvokableFactory::class, - 'leagueflysystemadapternulladapter' => InvokableFactory::class, - ]; - public function validate($instance): void { if (! $instance instanceof $this->instanceOf) { diff --git a/src/Service/Factory/AdapterManagerFactory.php b/src/Service/Factory/AdapterManagerFactory.php index 23dea21..a608d6f 100644 --- a/src/Service/Factory/AdapterManagerFactory.php +++ b/src/Service/Factory/AdapterManagerFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,93 +19,24 @@ namespace BsbFlysystem\Service\Factory; -use BsbFlysystem\Adapter\Factory\AwsS3v3AdapterFactory; -use BsbFlysystem\Adapter\Factory\AzureAdapterFactory; -use BsbFlysystem\Adapter\Factory\DropboxAdapterFactory; -use BsbFlysystem\Adapter\Factory\FtpAdapterFactory; -use BsbFlysystem\Adapter\Factory\FtpdAdapterFactory; -use BsbFlysystem\Adapter\Factory\GoogleCloudDriveAdapterFactory; -use BsbFlysystem\Adapter\Factory\LocalAdapterFactory; -use BsbFlysystem\Adapter\Factory\RackspaceAdapterFactory; -use BsbFlysystem\Adapter\Factory\ReplicateAdapterFactory; -use BsbFlysystem\Adapter\Factory\SftpAdapterFactory; -use BsbFlysystem\Adapter\Factory\VfsAdapterFactory; -use BsbFlysystem\Adapter\Factory\WebDAVAdapterFactory; -use BsbFlysystem\Adapter\Factory\ZipArchiveAdapterFactory; -use BsbFlysystem\Exception\UnexpectedValueException; use BsbFlysystem\Service\AdapterManager; -use Laminas\ServiceManager\Factory\InvokableFactory; -use Laminas\Stdlib\ArrayUtils; -use League\Flysystem\Adapter\NullAdapter; use Psr\Container\ContainerInterface; class AdapterManagerFactory { - /** - * @var array mapping adapter types to plugin configuration - */ - protected $adapterMap = [ - 'factories' => [ - 'awss3v3' => AwsS3v3AdapterFactory::class, - 'azure' => AzureAdapterFactory::class, - 'dropbox' => DropboxAdapterFactory::class, - 'ftp' => FtpAdapterFactory::class, - 'ftpd' => FtpdAdapterFactory::class, - 'googlecloudstorage' => GoogleCloudDriveAdapterFactory::class, - 'local' => LocalAdapterFactory::class, - 'rackspace' => RackspaceAdapterFactory::class, - 'replicate' => ReplicateAdapterFactory::class, - 'sftp' => SftpAdapterFactory::class, - 'webdav' => WebDAVAdapterFactory::class, - 'ziparchive' => ZipArchiveAdapterFactory::class, - 'vfs' => VfsAdapterFactory::class, - 'null' => InvokableFactory::class, - ], - 'aliases' => [ - 'null' => NullAdapter::class, - ], - ]; - - public function createService(ContainerInterface $container): AdapterManager - { - if (method_exists($container, 'getServiceLocator')) { - $container = $container->getServiceLocator(); - } - - return $this($container, null); - } - - public function __invoke(ContainerInterface $container, $requestedName, array $options = null): AdapterManager + public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): AdapterManager { - $config = $container->get('config'); - $config = $config['bsb_flysystem']; + $config = ($container->has('config') ? $container->get('config') : [])['bsb_flysystem'] ?? []; + $adapters = $config['adapters'] ?? []; $serviceConfig = $config['adapter_manager']['config'] ?? []; - $adapterMap = $this->adapterMap; - - if (isset($config['adapter_map'])) { - $adapterMap = ArrayUtils::merge($this->adapterMap, $config['adapter_map']); - } - - foreach ($config['adapters'] as $name => $adapterConfig) { - if (! isset($adapterConfig['type'])) { - throw new UnexpectedValueException(sprintf("Missing 'type' key for the adapter '%s' configuration", $name)); - } - - $type = strtolower($adapterConfig['type']); - - if (! \in_array($type, array_keys($adapterMap['factories']), false)) { - throw new UnexpectedValueException(sprintf("Unknown adapter type '%s'", $type)); - } - foreach (array_keys($adapterMap) as $serviceKind) { - if (isset($adapterMap[$serviceKind][$type])) { - $serviceConfig[$serviceKind][$name] = $adapterMap[$serviceKind][$type]; + foreach ($adapters as $name => $adapterConfig) { + \assert( + \array_key_exists('factory', $adapterConfig), + "Option 'factory' must be defined in an adapter configuration" + ); - if (isset($adapterConfig['shared'])) { - $serviceConfig['shared'][$name] = filter_var($adapterConfig['shared'], FILTER_VALIDATE_BOOLEAN); - } - } - } + $serviceConfig['factories'][$name] = $adapterConfig['factory']; } return new AdapterManager($container, $serviceConfig); diff --git a/src/Service/Factory/FilesystemManagerFactory.php b/src/Service/Factory/FilesystemManagerFactory.php index 2cbace9..1713e25 100644 --- a/src/Service/Factory/FilesystemManagerFactory.php +++ b/src/Service/Factory/FilesystemManagerFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -25,20 +25,15 @@ class FilesystemManagerFactory { - public function createService(ContainerInterface $container): FilesystemManager - { - return $this($container, null); - } - public function __invoke(ContainerInterface $container, $requestedName, array $options = null): FilesystemManager { - $config = $container->get('config'); - $config = $config['bsb_flysystem']['filesystems']; - $serviceConfig = []; - foreach ($config as $key => $filesystems) { - $serviceConfig['factories'][$key] = FilesystemFactory::class; - $serviceConfig['shared'][$key] = isset($filesystems['shared']) ? (bool) $filesystems['shared'] : true; - } + $filesystems = ($container->has('config') ? $container->get('config') : [])['bsb_flysystem']['filesystems'] ?? []; + + $serviceConfig = array_reduce(array_keys($filesystems), function (array $serviceConfig, string $name) { + $serviceConfig['factories'][$name] = FilesystemFactory::class; + + return $serviceConfig; + }, ['factories' => []]); return new FilesystemManager($container, $serviceConfig); } diff --git a/src/Service/FilesystemManager.php b/src/Service/FilesystemManager.php index 14ced3e..57618a0 100644 --- a/src/Service/FilesystemManager.php +++ b/src/Service/FilesystemManager.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,24 +22,14 @@ use BsbFlysystem\Exception\RuntimeException; use Laminas\ServiceManager\AbstractPluginManager; use Laminas\ServiceManager\Exception; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\Filesystem; class FilesystemManager extends AbstractPluginManager { /** * @var string */ - protected $instanceOf = FilesystemInterface::class; - - /** - * @var bool - */ - protected $shareByDefault = true; - - /** - * @var bool - */ - protected $sharedByDefault = true; + protected $instanceOf = Filesystem::class; public function validate($instance): void { diff --git a/test/Adapter/Factory/AbstractAdapterFactoryTest.php b/test/Adapter/Factory/AbstractAdapterFactoryTest.php index f3826da..e3e8982 100644 --- a/test/Adapter/Factory/AbstractAdapterFactoryTest.php +++ b/test/Adapter/Factory/AbstractAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,25 +22,22 @@ use BsbFlysystemTest\Assets\SimpleAdapterFactory; use Laminas\ServiceManager\ServiceManager; use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; class AbstractAdapterFactoryTest extends TestCase { /** - * @var ReflectionProperty + * @var \ReflectionProperty */ protected $property; /** - * @var ReflectionMethod + * @var \ReflectionMethod */ protected $method; public function setup(): void { - $class = new ReflectionClass(SimpleAdapterFactory::class); + $class = new \ReflectionClass(SimpleAdapterFactory::class); $this->property = $class->getProperty('options'); $this->property->setAccessible(true); diff --git a/test/Adapter/Factory/AwsS3v3AdapterFactoryTest.php b/test/Adapter/Factory/AwsS3v3AdapterFactoryTest.php index 1379e3a..fea2a0e 100644 --- a/test/Adapter/Factory/AwsS3v3AdapterFactoryTest.php +++ b/test/Adapter/Factory/AwsS3v3AdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -21,199 +21,99 @@ use Aws\Command; use BsbFlysystem\Adapter\Factory\AwsS3v3AdapterFactory; +use BsbFlysystem\Exception\RequirementsException; use BsbFlysystemTest\Bootstrap; -use League\Flysystem\AwsS3v3\AwsS3Adapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use League\Flysystem\AwsS3V3\AwsS3V3Adapter; +use League\Flysystem\AwsS3V3\VisibilityConverter; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; -class AwsS3v3AdapterFactoryTest extends TestCase +class AwsS3v3AdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass('BsbFlysystem\Adapter\Factory\AwsS3v3AdapterFactory'); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new AwsS3v3AdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } public function testCreateService(): void { - $this->markTestSkipped('Skipped because Aws3Sv2 and Aws3Sv3 are not compatible.'); - $sm = Bootstrap::getServiceManager(); $factory = new AwsS3v3AdapterFactory(); - $adapter = $factory($sm, 'awss3_default'); + $adapter = $factory($sm, 'awss3v3_default'); - $this->assertInstanceOf('League\Flysystem\AwsS3v3\AwsS3v3Adapter', $adapter); + $this->assertInstanceOf(AwsS3V3Adapter::class, $adapter); } - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new AwsS3v3AdapterFactory($options); + public function testGettingFromServiceManager(): void + { + $factory = new AwsS3v3AdapterFactory(); - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->method->invokeArgs($factory, []); + $visibility = $this->prophet->prophesize(VisibilityConverter::class); + $container->get('a-visibility')->willReturn($visibility->reveal()); - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); - public function validateConfigProvider(): array - { - return [ - [ - [], - [], - 'UnexpectedValueException', - "Missing 'credentials' as array", - ], - [ - [ - 'iam' => false, - ], - [], - 'UnexpectedValueException', - "Missing 'credentials' as array", - ], - [ - [ - 'iam' => true, - ], - [], - 'UnexpectedValueException', - "Missing 'region' as option", - ], - [ - [ - 'credentials' => [], - ], - [], - 'UnexpectedValueException', - "Missing 'key' as option", - ], - [ - [ - 'credentials' => [ - 'key' => 'foo', - ], + $adapter = $factory($container->reveal(), 'awss3v3_default', [ + 'client' => [ + 'credentials' => [ + 'key' => 'abc', + 'secret' => 'xxx', ], - [], - 'UnexpectedValueException', - "Missing 'secret' as option", + 'region' => 'eu-west-1', + 'version' => 'latest', ], - [ - [ - 'credentials' => [ - 'key' => 'foo', - 'secret' => 'bar', - ], - ], - [], - 'UnexpectedValueException', - "Missing 'region' as option", - ], - [ - [ - 'iam' => true, - 'credentials' => [ - 'key' => 'foo', - 'secret' => 'bar', - ], - ], - [], - 'UnexpectedValueException', - "Missing 'region' as option", - ], - [ - [ - 'credentials' => [ - 'key' => 'foo', - 'secret' => 'bar', - ], - 'region' => 'baz', - ], - [], - 'UnexpectedValueException', - "Missing 'bucket' as option", - ], - [ - [ - 'credentials' => [ - 'key' => 'abc', - 'secret' => 'def', - ], - 'region' => 'ghi', - 'bucket' => 'jkl', - ], - [ - 'credentials' => [ - 'key' => 'abc', - 'secret' => 'def', - ], - 'region' => 'ghi', - 'bucket' => 'jkl', - 'prefix' => '', - 'request.options' => [], - 'version' => 'latest', - 'streamReads' => true, - ], - null, - null, - ], - ]; + 'bucket' => 'xxxxx', + 'visibility' => 'a-visibility', + 'mimeTypeDetector' => 'a-mime-type-detector', + ]); + + $this->assertInstanceOf(AwsS3V3Adapter::class, $adapter); } public function testCreateServiceWithRequestOptions(): void { - $this->markTestSkipped('Skipped because Aws3Sv2 and Aws3Sv3 are not compatible.'); - $options = [ - 'credentials' => [ - 'key' => 'abc', - 'secret' => 'def', + 'client' => [ + 'credentials' => [ + 'key' => 'abc', + 'secret' => 'def', + ], + 'region' => 'ghi', + 'http' => [ + 'timeout' => 1, + ], ], - 'region' => 'ghi', 'bucket' => 'jkl', - 'request.options' => [ - 'timeout' => 1, - ], ]; $sm = Bootstrap::getServiceManager(); $factory = new AwsS3v3AdapterFactory($options); - /** @var AwsS3Adapter $adapter */ - $adapter = $factory($sm, 'awss3_default'); + /** @var AwsS3V3Adapter $adapter */ + $adapter = $factory($sm, 'awss3v3_default'); + + $reflectionProperty = new \ReflectionProperty($adapter, 'client'); + $reflectionProperty->setAccessible(true); + $client = $reflectionProperty->getValue($adapter); + $reflectionProperty->setAccessible(false); /** @var Command $command */ - $command = $adapter->getClient()->getCommand('GetObject'); + $command = $client->getCommand('GetObject'); self::assertTrue($command->hasParam('@http')); self::assertEquals(['timeout' => 1], $command['@http']); diff --git a/test/Adapter/Factory/AzureAdapterFactoryTest.php b/test/Adapter/Factory/AzureAdapterFactoryTest.php deleted file mode 100644 index 96ff8ab..0000000 --- a/test/Adapter/Factory/AzureAdapterFactoryTest.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Adapter\Factory; - -use BsbFlysystem\Adapter\Factory\AzureAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Azure\AzureAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; - -class AzureAdapterFactoryTest extends TestCase -{ - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void - { - $class = new ReflectionClass(AzureAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } - - public function testCreateService(): void - { - $this->markTestSkipped('Skipped due to https://github.com/thephpleague/flysystem-azure/pull/16'); - - $sm = Bootstrap::getServiceManager(); - $factory = new AzureAdapterFactory( - [ - 'account-name' => 'foo', - 'account-key' => 'bar', - 'container' => 'container', - ] - ); - - $adapter = $factory($sm, 'azure_default'); - - $this->assertInstanceOf(AzureAdapter::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new AzureAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - [], - 'UnexpectedValueException', - "Missing 'account-name' as option", - ], - [ - ['account-name' => 'foo'], - [], - 'UnexpectedValueException', - "Missing 'account-key' as option", - ], - [ - [ - 'account-name' => 'foo', - 'account-key' => 'bar', - ], - [], - 'UnexpectedValueException', - "Missing 'container' as option", - ], - [ - [ - 'account-name' => 'foo', - 'account-key' => 'bar', - 'container' => 'container', - ], - [ - 'account-name' => 'foo', - 'account-key' => 'bar', - 'container' => 'container', - ], - null, - null, - ], - ]; - } -} diff --git a/test/Adapter/Factory/AzureBlobStorageAdapterFactoryTest.php b/test/Adapter/Factory/AzureBlobStorageAdapterFactoryTest.php new file mode 100644 index 0000000..6c13f57 --- /dev/null +++ b/test/Adapter/Factory/AzureBlobStorageAdapterFactoryTest.php @@ -0,0 +1,104 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystemTest\Adapter\Factory; + +use BsbFlysystem\Adapter\Factory\AzureBlobStorageAdapterFactory; +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\AzureBlobStorage\AzureBlobStorageAdapter; +use League\MimeTypeDetection\MimeTypeDetector; +use MicrosoftAzure\Storage\Blob\BlobRestProxy; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; + +class AzureBlobStorageAdapterFactoryTest extends BaseAdapterFactory +{ + use PHPMock; + + public function testClassExists(): void + { + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new AzureBlobStorageAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); + + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); + } + + public function testGettingFromServiceManager(): void + { + $factory = new AzureBlobStorageAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); + + $client = $this->prophet->prophesize(BlobRestProxy::class); + $container->get('a-client')->willReturn($client->reveal()); + + $adapter = $factory($container->reveal(), 'azureblobstorage_default', [ + 'client' => 'a-client', + 'container' => 'xxx', + 'mimeTypeDetector' => 'a-mime-type-detector', + ]); + + $this->assertInstanceOf(AzureBlobStorageAdapter::class, $adapter); + } + + public function testClientOptions(): void + { + $factory = new AzureBlobStorageAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $adapter = $factory($container->reveal(), 'azureblobstorage_default', [ + 'container' => 'xxx', + 'client' => ['connectionString' => 'DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx'], + ]); + + $this->assertInstanceOf(AzureBlobStorageAdapter::class, $adapter); + } + + public function testServiceSettingsOptions(): void + { + $factory = new AzureBlobStorageAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $adapter = $factory($container->reveal(), 'azureblobstorage_default', [ + 'container' => 'xxx', + 'client' => ['connectionString' => 'DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx'], + 'serviceSettings' => [ + 'name' => 'xxx', + 'key' => 'xxx', + 'blobEndpointUri' => 'https://xxx.blob.core.windows.net/', + 'queueEndpointUri' => 'https://xxx.queue.core.windows.net/', + 'tableEndpointUri' => 'https://xxx.table.core.windows.net/', + 'fileEndpointUri' => 'https://xxx.file.core.windows.net/', ], + ]); + + $this->assertInstanceOf(AzureBlobStorageAdapter::class, $adapter); + } +} diff --git a/test/Adapter/Factory/BaseAdapterFactory.php b/test/Adapter/Factory/BaseAdapterFactory.php new file mode 100644 index 0000000..16cacd4 --- /dev/null +++ b/test/Adapter/Factory/BaseAdapterFactory.php @@ -0,0 +1,38 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystemTest\Adapter\Factory; + +use PHPUnit\Framework\TestCase; +use Prophecy\Prophet; + +class BaseAdapterFactory extends TestCase +{ + protected Prophet $prophet; + + protected function setUp(): void + { + $this->prophet = new Prophet(); + } + + protected function tearDown(): void + { + $this->prophet->checkPredictions(); + } +} diff --git a/test/Adapter/Factory/DropboxAdapterFactoryTest.php b/test/Adapter/Factory/DropboxAdapterFactoryTest.php index b157eae..67adcd5 100644 --- a/test/Adapter/Factory/DropboxAdapterFactoryTest.php +++ b/test/Adapter/Factory/DropboxAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,83 +20,60 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\DropboxAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use BsbFlysystem\Exception\RequirementsException; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; use Spatie\FlysystemDropbox\DropboxAdapter; -class DropboxAdapterFactoryTest extends TestCase +class DropboxAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(DropboxAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new DropboxAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - public function testCreateService(): void + public function testGettingFromServiceManager(): void { - $sm = Bootstrap::getServiceManager(); $factory = new DropboxAdapterFactory(); - $adapter = $factory($sm, 'dropbox_default'); + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->assertInstanceOf(DropboxAdapter::class, $adapter); - } + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); + + $client = $this->prophet->prophesize(\Spatie\Dropbox\Client::class); + $container->get('a-client')->willReturn($client->reveal()); + + $adapter = $factory($container->reveal(), 'dropbox_default', [ + 'client' => 'a-client', + 'mimeTypeDetector' => 'a-mime-type-detector', + ]); - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new DropboxAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } + $this->assertInstanceOf(DropboxAdapter::class, $adapter); } - public function validateConfigProvider(): array + public function testClientOptionsAsArray(): void { - return [ - [ - [], - [], - 'UnexpectedValueException', - "Missing 'access_token' as option", - ], - [ - ['access_token' => 'foo'], - ['access_token' => 'foo', 'prefix' => null], - null, - null, - ], - ]; + $factory = new DropboxAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $adapter = $factory($container->reveal(), 'dropbox_default', [ + 'client' => ['accessTokenOrAppCredentials' => 'string'], + ]); + + $this->assertInstanceOf(DropboxAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/FtpAdapterFactoryTest.php b/test/Adapter/Factory/FtpAdapterFactoryTest.php index e7381de..e4236ea 100644 --- a/test/Adapter/Factory/FtpAdapterFactoryTest.php +++ b/test/Adapter/Factory/FtpAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,101 +20,63 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\FtpAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Adapter\Ftp; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; - -class FtpAdapterFactoryTest extends TestCase +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\Ftp\ConnectivityChecker; +use League\Flysystem\Ftp\FtpAdapter; +use League\Flysystem\Ftp\FtpConnectionProvider; +use League\Flysystem\UnixVisibility\VisibilityConverter; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; + +class FtpAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(FtpAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new FtpAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - public function testCreateService(): void + public function testGettingFromServiceManager(): void { - $sm = Bootstrap::getServiceManager(); $factory = new FtpAdapterFactory(); - $adapter = $factory($sm, 'ftp_default'); + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->assertInstanceOf(Ftp::class, $adapter); - } + $connectionProvider = $this->prophet->prophesize(FtpConnectionProvider::class); + $container->get('a-connection-provider')->willReturn($connectionProvider->reveal()); - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new FtpAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } + $connectivityChecker = $this->prophet->prophesize(ConnectivityChecker::class); + $container->get('a-connectivity-checker')->willReturn($connectivityChecker->reveal()); - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'host' as option", - ], - [ - ['host' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'port' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'username' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'password' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - null, - null, + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); + + $visibility = $this->prophet->prophesize(VisibilityConverter::class); + $container->get('a-visibility')->willReturn($visibility->reveal()); + + $adapter = $factory($container->reveal(), 'ftp_default', [ + 'connectionOptions' => [ + 'host' => 'localhost', + 'root' => '/path/to/root', + 'username' => 'username', + 'password' => 'password', ], - ]; + 'connectionProvider' => 'a-connection-provider', + 'connectivityChecker' => 'a-connectivity-checker', + 'mimeTypeDetector' => 'a-mime-type-detector', + 'visibilityConverter' => 'a-visibility', + ]); + + $this->assertInstanceOf(FtpAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/FtpdAdapterFactoryTest.php b/test/Adapter/Factory/FtpdAdapterFactoryTest.php deleted file mode 100644 index be9b619..0000000 --- a/test/Adapter/Factory/FtpdAdapterFactoryTest.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Adapter\Factory; - -use BsbFlysystem\Adapter\Factory\FtpdAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Adapter\Ftp; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; - -class FtpdAdapterFactoryTest extends TestCase -{ - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void - { - $class = new ReflectionClass(FtpdAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } - - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); - $factory = new FtpdAdapterFactory(); - - $adapter = $factory($sm, 'ftpd_default'); - - $this->assertInstanceOf(Ftp::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new FtpdAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'host' as option", - ], - [ - ['host' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'port' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'username' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'password' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - null, - null, - ], - ]; - } -} diff --git a/test/Adapter/Factory/GoogleCloudDriveAdapterFactoryTest.php b/test/Adapter/Factory/GoogleCloudDriveAdapterFactoryTest.php deleted file mode 100644 index 25d1351..0000000 --- a/test/Adapter/Factory/GoogleCloudDriveAdapterFactoryTest.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Adapter\Factory; - -use BsbFlysystem\Adapter\Factory\GoogleCloudDriveAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; -use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter; - -class GoogleCloudDriveAdapterFactoryTest extends TestCase -{ - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void - { - $class = new ReflectionClass(GoogleCloudDriveAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } - - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); - $factory = new GoogleCloudDriveAdapterFactory(); - - $adapter = $factory($sm, 'googleclouddrive_default'); - - $this->assertInstanceOf(GoogleStorageAdapter::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new GoogleCloudDriveAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'project_id' as option", - ], - [ - ['project_id' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'bucket' as option", - ], - [ - ['project_id' => 'foo', 'bucket' => 'bar'], - ['project_id' => 'foo', 'bucket' => 'bar'], - null, - null, - ], - ]; - } -} diff --git a/test/Adapter/Factory/GoogleCloudStorageAdapterFactoryTest.php b/test/Adapter/Factory/GoogleCloudStorageAdapterFactoryTest.php new file mode 100644 index 0000000..c201a29 --- /dev/null +++ b/test/Adapter/Factory/GoogleCloudStorageAdapterFactoryTest.php @@ -0,0 +1,71 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystemTest\Adapter\Factory; + +use BsbFlysystem\Adapter\Factory\GoogleCloudStorageAdapterFactory; +use BsbFlysystem\Exception\RequirementsException; +use Google\Cloud\Storage\Bucket; +use League\Flysystem\GoogleCloudStorage\GoogleCloudStorageAdapter; +use League\Flysystem\GoogleCloudStorage\VisibilityHandler; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; + +class GoogleCloudStorageAdapterFactoryTest extends BaseAdapterFactory +{ + use PHPMock; + + public function testClassExists(): void + { + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new GoogleCloudStorageAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); + + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); + } + + public function testGettingFromServiceManager(): void + { + $factory = new GoogleCloudStorageAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $bucket = $this->prophet->prophesize(Bucket::class); + $container->get('a-bucket')->willReturn($bucket->reveal()); + + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); + + $visibility = $this->prophet->prophesize(VisibilityHandler::class); + $container->get('a-visibility')->willReturn($visibility->reveal()); + + $adapter = $factory($container->reveal(), 'googlecloudstorage_default', [ + 'bucket' => 'a-bucket', + 'mimeTypeDetector' => 'a-mime-type-detector', + 'visibilityHandler' => 'a-visibility', + ]); + + $this->assertInstanceOf(GoogleCloudStorageAdapter::class, $adapter); + } +} diff --git a/test/Adapter/Factory/InMemoryAdapterFactoryTest.php b/test/Adapter/Factory/InMemoryAdapterFactoryTest.php new file mode 100644 index 0000000..b04587e --- /dev/null +++ b/test/Adapter/Factory/InMemoryAdapterFactoryTest.php @@ -0,0 +1,61 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +namespace BsbFlysystemTest\Adapter\Factory; + +use BsbFlysystem\Adapter\Factory\InMemoryAdapterFactory; +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; + +class InMemoryAdapterFactoryTest extends BaseAdapterFactory +{ + use PHPMock; + + public function testClassExists(): void + { + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new InMemoryAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); + + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); + } + + public function testGettingFromServiceManager(): void + { + $factory = new InMemoryAdapterFactory(); + + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); + + $adapter = $factory($container->reveal(), 'inmemory_default', [ + 'mimeTypeDetector' => 'a-mime-type-detector', + ]); + + $this->assertInstanceOf(InMemoryFilesystemAdapter::class, $adapter); + } +} diff --git a/test/Adapter/Factory/LocalAdapterFactoryTest.php b/test/Adapter/Factory/LocalAdapterFactoryTest.php index e4aea83..6b14e78 100644 --- a/test/Adapter/Factory/LocalAdapterFactoryTest.php +++ b/test/Adapter/Factory/LocalAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,83 +20,34 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\LocalAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Adapter\Local; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use League\Flysystem\Local\LocalFilesystemAdapter; +use League\Flysystem\UnixVisibility\VisibilityConverter; +use League\MimeTypeDetection\MimeTypeDetector; +use Psr\Container\ContainerInterface; -class LocalAdapterFactoryTest extends TestCase +class LocalAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void - { - $class = new ReflectionClass(LocalAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } - - public function testCreateService(): void + public function testGettingFromServiceManager(): void { - $sm = Bootstrap::getServiceManager(); $factory = new LocalAdapterFactory(); - $adapter = $factory($sm, 'local_default'); + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->assertInstanceOf(Local::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new LocalAdapterFactory($options); + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } + $visibility = $this->prophet->prophesize(VisibilityConverter::class); + $visibility->defaultForDirectories()->willReturn(0755); + $container->get('a-visibility')->willReturn($visibility->reveal()); - $this->method->invokeArgs($factory, []); + $adapter = $factory($container->reveal(), 'local_default', [ + 'location' => 'a-location', + 'mimeTypeDetector' => 'a-mime-type-detector', + 'visibility' => 'a-visibility', + 'lazyRootCreation' => true, + ]); - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'root' as option", - ], - [ - ['root' => '.'], - ['root' => '.'], - null, - null, - ], - ]; + $this->assertInstanceOf(LocalFilesystemAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/RackspaceAdapterFactoryTest.php b/test/Adapter/Factory/RackspaceAdapterFactoryTest.php deleted file mode 100644 index 31362bd..0000000 --- a/test/Adapter/Factory/RackspaceAdapterFactoryTest.php +++ /dev/null @@ -1,202 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Adapter\Factory; - -use BsbFlysystem\Adapter\Factory\RackspaceAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Rackspace\RackspaceAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; - -class RackspaceAdapterFactoryTest extends TestCase -{ - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void - { - $class = new ReflectionClass(RackspaceAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } - - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); - $factory = new RackspaceAdapterFactory(); - - $adapter = $factory($sm, 'rackspace_default'); - - $this->assertInstanceOf(RackspaceAdapter::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new RackspaceAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - [], - 'UnexpectedValueException', - "Missing 'url' as option", - ], - [ - ['url' => 'some_url'], - [], - 'UnexpectedValueException', - "Missing 'secret' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => 'secret', - ], - [], - 'UnexpectedValueException', - "Missing 'secret' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [], - ], - [], - 'UnexpectedValueException', - "Missing 'objectstore' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [ - 'username' => 'foo', - 'password' => 'foo', - 'tenant_name' => 'foo', - ], - 'objectstore' => 'bar', - ], - [], - 'UnexpectedValueException', - "Missing 'objectstore' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [ - 'username' => 'foo', - 'password' => 'foo', - 'tenant_name' => 'foo', - ], - 'objectstore' => [], - ], - [], - 'UnexpectedValueException', - "Missing 'objectstore.name' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [ - 'username' => 'foo', - 'password' => 'foo', - 'tenant_name' => 'foo', - ], - 'objectstore' => [ - 'name' => 'foo', - ], - ], - [], - 'UnexpectedValueException', - "Missing 'objectstore.region' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [], - 'objectstore' => [ - 'name' => 'foo', - 'region' => 'foo', - ], - ], - [], - 'UnexpectedValueException', - "Missing 'objectstore.container' as option", - ], - [ - [ - 'url' => 'some_url', - 'secret' => [], - 'objectstore' => [ - 'name' => 'foo', - 'region' => 'foo', - 'container' => 'foo', - ], - ], - [ - 'url' => 'some_url', - 'secret' => [], - 'objectstore' => [ - 'name' => 'foo', - 'region' => 'foo', - 'container' => 'foo', - 'url_type' => null, // added - ], - 'options' => [], // added - 'prefix' => null, // added - ], - null, - null, - ], - ]; - } -} diff --git a/test/Adapter/Factory/ReplicateAdapterFactoryTest.php b/test/Adapter/Factory/ReplicateAdapterFactoryTest.php index 035c657..52e2518 100644 --- a/test/Adapter/Factory/ReplicateAdapterFactoryTest.php +++ b/test/Adapter/Factory/ReplicateAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,90 +19,51 @@ namespace BsbFlysystemTest\Adapter\Factory; +use Ajgl\Flysystem\Replicate\ReplicateFilesystemAdapter; use BsbFlysystem\Adapter\Factory\ReplicateAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Replicate\ReplicateAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use BsbFlysystem\Exception\RequirementsException; +use BsbFlysystem\Service\AdapterManager; +use League\Flysystem\FilesystemAdapter; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; -class ReplicateAdapterFactoryTest extends TestCase +class ReplicateAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(ReplicateAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); + + $factory = new ReplicateAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - public function testCreateService(): void + public function testGettingFromServiceManager(): void { - $sm = Bootstrap::getServiceManager(); $factory = new ReplicateAdapterFactory(); - $adapter = $factory($sm, 'replicate_default'); + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->assertInstanceOf(ReplicateAdapter::class, $adapter); - } + $manager = $this->prophet->prophesize(AdapterManager::class); + $container->get(AdapterManager::class)->willReturn($manager->reveal()); - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new ReplicateAdapterFactory($options); + $source = $this->prophet->prophesize(FilesystemAdapter::class); + $manager->get('a-source')->willReturn($source->reveal()); - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } + $replica = $this->prophet->prophesize(FilesystemAdapter::class); + $manager->get('a-replica')->willReturn($replica->reveal()); - $this->method->invokeArgs($factory, []); + $adapter = $factory($container->reveal(), 'replicate_default', [ + 'source' => 'a-source', + 'replica' => 'a-replica', + ]); - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } - - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'source' as option", - ], - [ - ['source' => 'local->default'], - null, - 'UnexpectedValueException', - "Missing 'replicate' as option", - ], - [ - ['source' => 'local->default', 'replicate' => 'zip->default'], - ['source' => 'local->default', 'replicate' => 'zip->default'], - null, - null, - ], - ]; + $this->assertInstanceOf(ReplicateFilesystemAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/SftpAdapterFactoryTest.php b/test/Adapter/Factory/SftpAdapterFactoryTest.php index b2b5ea0..0f7d3f2 100644 --- a/test/Adapter/Factory/SftpAdapterFactoryTest.php +++ b/test/Adapter/Factory/SftpAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,107 +20,57 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\SftpAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Sftp\SftpAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; - -class SftpAdapterFactoryTest extends TestCase +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\PhpseclibV3\ConnectivityChecker; +use League\Flysystem\PhpseclibV3\SftpAdapter; +use League\Flysystem\UnixVisibility\VisibilityConverter; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; + +class SftpAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; - - /** - * @var ReflectionMethod - */ - protected $method; + use PHPMock; - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(SftpAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); + $factory = new SftpAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); + + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - public function testCreateService(): void + public function testGettingFromServiceManager(): void { - $sm = Bootstrap::getServiceManager(); $factory = new SftpAdapterFactory(); - $adapter = $factory($sm, 'sftp_default'); + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->assertInstanceOf(SftpAdapter::class, $adapter); - } - - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new SftpAdapterFactory($options); + $connectivityChecker = $this->prophet->prophesize(ConnectivityChecker::class); + $container->get('a-connectivity-checker')->willReturn($connectivityChecker->reveal()); - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); - $this->method->invokeArgs($factory, []); - - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } + $visibility = $this->prophet->prophesize(VisibilityConverter::class); + $container->get('a-visibility')->willReturn($visibility->reveal()); - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'host' as option", - ], - [ - ['host' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'port' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo'], - null, - 'UnexpectedValueException', - "Missing 'username' as option", - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo'], - null, - 'UnexpectedValueException', - "Missing either 'password' or 'privateKey' as option", + $adapter = $factory($container->reveal(), 'sftp_default', [ + 'connectionProvider' => [ + 'host' => 'localhost', + 'username' => 'username', + 'connectivityChecker' => 'a-connectivity-checker', ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'password' => 'foo'], - null, - null, - ], - [ - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'privateKey' => 'foo'], - ['host' => 'foo', 'port' => 'foo', 'username' => 'foo', 'privateKey' => 'foo'], - null, - null, - ], - ]; + 'root' => '/path/to/root', + 'mimeTypeDetector' => 'a-mime-type-detector', + 'visibilityConverter' => 'a-visibility', + ]); + + $this->assertInstanceOf(SftpAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/VfsAdapterFactoryTest.php b/test/Adapter/Factory/VfsAdapterFactoryTest.php deleted file mode 100644 index de12b59..0000000 --- a/test/Adapter/Factory/VfsAdapterFactoryTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Adapter\Factory; - -use BsbFlysystem\Adapter\Factory\VfsAdapterFactory; -use BsbFlysystemTest\Bootstrap; -use League\Flysystem\Vfs\VfsAdapter; -use PHPUnit\Framework\TestCase; - -class VfsAdapterFactoryTest extends TestCase -{ - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); - $factory = new VfsAdapterFactory(); - - $adapter = $factory($sm, null); - - $this->assertInstanceOf(VfsAdapter::class, $adapter); - } -} diff --git a/test/Adapter/Factory/WebDAVAdapterFactoryTest.php b/test/Adapter/Factory/WebDAVAdapterFactoryTest.php index c4d4279..12905be 100644 --- a/test/Adapter/Factory/WebDAVAdapterFactoryTest.php +++ b/test/Adapter/Factory/WebDAVAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,83 +20,40 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\WebDAVAdapterFactory; -use BsbFlysystemTest\Bootstrap; +use BsbFlysystem\Exception\RequirementsException; use League\Flysystem\WebDAV\WebDAVAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; -class WebDAVAdapterFactoryTest extends TestCase +class WebDAVAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(WebDAVAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); $factory = new WebDAVAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $adapter = $factory($sm, 'webdav_default'); - - $this->assertInstanceOf(WebDAVAdapter::class, $adapter); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new WebDAVAdapterFactory($options); - - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } - - $this->method->invokeArgs($factory, []); + public function testGettingFromServiceManager(): void + { + $factory = new WebDAVAdapterFactory(); - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'baseUri' as option", + $adapter = $factory($container->reveal(), 'webdav_default', [ + 'client' => [ + 'baseUri' => 'a-base-url', ], - [ - ['baseUri' => 'foo'], - ['baseUri' => 'foo', 'prefix' => null], - null, - null, - ], - ]; + ]); + + $this->assertInstanceOf(WebDAVAdapter::class, $adapter); } } diff --git a/test/Adapter/Factory/ZipArchiveAdapterFactoryTest.php b/test/Adapter/Factory/ZipArchiveAdapterFactoryTest.php index f077a9f..7b4d630 100644 --- a/test/Adapter/Factory/ZipArchiveAdapterFactoryTest.php +++ b/test/Adapter/Factory/ZipArchiveAdapterFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,83 +20,51 @@ namespace BsbFlysystemTest\Adapter\Factory; use BsbFlysystem\Adapter\Factory\ZipArchiveAdapterFactory; -use BsbFlysystemTest\Bootstrap; +use BsbFlysystem\Exception\RequirementsException; +use League\Flysystem\UnixVisibility\VisibilityConverter; use League\Flysystem\ZipArchive\ZipArchiveAdapter; -use PHPUnit\Framework\TestCase; -use ReflectionClass; -use ReflectionMethod; -use ReflectionProperty; +use League\MimeTypeDetection\MimeTypeDetector; +use phpmock\phpunit\PHPMock; +use Psr\Container\ContainerInterface; -class ZipArchiveAdapterFactoryTest extends TestCase +class ZipArchiveAdapterFactoryTest extends BaseAdapterFactory { - /** - * @var ReflectionProperty - */ - protected $property; + use PHPMock; - /** - * @var ReflectionMethod - */ - protected $method; - - public function setup(): void + public function testClassExists(): void { - $class = new ReflectionClass(ZipArchiveAdapterFactory::class); - $this->property = $class->getProperty('options'); - $this->property->setAccessible(true); - - $this->method = $class->getMethod('validateConfig'); - $this->method->setAccessible(true); - } + $classExists = $this->getFunctionMock('BsbFlysystem\Adapter\Factory', 'class_exists'); + $classExists->expects($this->once())->willReturn(false); - public function testCreateService(): void - { - $sm = Bootstrap::getServiceManager(); $factory = new ZipArchiveAdapterFactory(); + $container = $this->prophet->prophesize(ContainerInterface::class); - $adapter = $factory($sm, 'zip_default'); - - $this->assertInstanceOf(ZipArchiveAdapter::class, $adapter); + $this->expectException(RequirementsException::class); + $factory->doCreateService($container->reveal()); } - /** - * @dataProvider validateConfigProvider - */ - public function testValidateConfig( - array $options, - ?array $expectedOptions, - ?string $expectedException, - ?string $expectedExceptionMessage - ): void { - $factory = new ZipArchiveAdapterFactory($options); + public function testGettingFromServiceManager(): void + { + $factory = new ZipArchiveAdapterFactory(); - if ($expectedException) { - $this->expectException($expectedException); - $this->expectExceptionMessage($expectedExceptionMessage); - } + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); - $this->method->invokeArgs($factory, []); + $mimeTypeDetector = $this->prophet->prophesize(MimeTypeDetector::class); + $container->get('a-mime-type-detector')->willReturn($mimeTypeDetector->reveal()); - if (\is_array($expectedOptions)) { - $this->assertEquals($expectedOptions, $this->property->getValue($factory)); - } - } + $visibility = $this->prophet->prophesize(VisibilityConverter::class); + $container->get('a-visibility')->willReturn($visibility->reveal()); - public function validateConfigProvider(): array - { - return [ - [ - [], - null, - 'UnexpectedValueException', - "Missing 'archive' as option", + $adapter = $factory($container->reveal(), 'zip_default', [ + 'zipArchiveProvider' => [ + 'filename' => 'test.zip', ], - [ - ['archive' => 'foo'], - ['archive' => 'foo', 'prefix' => null], - null, - null, - ], - ]; + 'root' => 'a-root', + 'mimeTypeDetector' => 'a-mime-type-detector', + 'visibility' => 'a-visibility', + ]); + + $this->assertInstanceOf(ZipArchiveAdapter::class, $adapter); } } diff --git a/test/Assets/Functions.php b/test/Assets/Functions.php index 4730cbb..9c8792d 100644 --- a/test/Assets/Functions.php +++ b/test/Assets/Functions.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,7 +19,7 @@ namespace BsbFlysystem\Filter\File; - function is_uploaded_file($filepath): bool - { - return realpath($filepath) === realpath(__DIR__ . '/test.txt'); - } +function is_uploaded_file($filepath): bool +{ + return realpath($filepath) === realpath(__DIR__ . '/test.txt'); +} diff --git a/test/Assets/SimpleAdapterFactory.php b/test/Assets/SimpleAdapterFactory.php index 1a6ec16..4578ae0 100644 --- a/test/Assets/SimpleAdapterFactory.php +++ b/test/Assets/SimpleAdapterFactory.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -20,19 +20,19 @@ namespace BsbFlysystemTest\Assets; use BsbFlysystem\Adapter\Factory\AbstractAdapterFactory; -use League\Flysystem\Adapter\NullAdapter; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use Psr\Container\ContainerInterface; class SimpleAdapterFactory extends AbstractAdapterFactory { - public function doCreateService(ContainerInterface $container): AdapterInterface + public function doCreateService(ContainerInterface $container): FilesystemAdapter { $this->mergeMvcConfig($container, func_get_arg(2)); $this->validateConfig(); - return new NullAdapter(); + return new InMemoryFilesystemAdapter(); } public function validateConfig(): void diff --git a/test/Assets/bsb_flysystem.global.php b/test/Assets/bsb_flysystem.global.php deleted file mode 100644 index c0ed89a..0000000 --- a/test/Assets/bsb_flysystem.global.php +++ /dev/null @@ -1,196 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -$abstractFactories = []; - -if (class_exists('Laminas\Cache\Service\StorageCacheAbstractServiceFactory')) { - $abstractFactories[] = 'Laminas\Cache\Service\StorageCacheAbstractServiceFactory'; -} - -return [ - 'bsb_flysystem' => [ - 'adapters' => [ - 'local_default' => [ - 'type' => 'local', - 'options' => [ - 'root' => './test/_build/files', - ], - ], - 'local_default_unshared' => [ - 'type' => 'local', - 'shared' => false, - 'options' => [ - 'root' => './test/_build/files', - ], - ], - 'null_default' => [ - 'type' => 'null', - 'options' => [], - ], - 'sftp_default' => [ - 'type' => 'sftp', - 'options' => [ - 'host' => 'xxxxx', - 'port' => 22, - 'username' => 'xxxxx', - 'password' => 'xxxxx', - 'timeout' => 10, - ], - ], - 'ftp_default' => [ - 'type' => 'ftp', - 'options' => [ - 'host' => 'xxxxx', - 'username' => 'xxxxx', - 'password' => 'xxxxx', - // optional config settings - 'port' => 21, - 'root' => '/', - 'passive' => true, - 'ssl' => false, - 'timeout' => 30, - ], - ], - 'ftpd_default' => [ - 'type' => 'ftpd', - 'options' => [ - 'host' => 'xxxxx', - 'username' => 'xxxxx', - 'password' => 'xxxxx', - // optional config settings - 'port' => 21, - 'root' => '/', - 'passive' => true, - 'ssl' => false, - 'timeout' => 30, - ], - ], - 'googleclouddrive_default' => [ - 'type' => 'ftpd', - 'options' => [ - 'project_id' => 'xxxxx', - 'bucket' => 'xxxxx', - ], - ], - 'zip_default' => [ - 'type' => 'ziparchive', - 'options' => [ - 'archive' => './test/_build/files.zip', - ], - ], - 'rackspace_default' => [ - 'type' => 'rackspace', - 'options' => [ - 'url' => 'http.xxxxx.xxx', - 'secret' => [ - 'username' => 'xxxxx', - 'password' => 'xxxxx', - 'tenant_name' => 'xxxxx', - ], - 'objectstore' => [ - 'name' => 'xxxxx', - 'region' => 'XX', - 'url_type' => 'publicURL', - 'container' => 'xxxxx', - ], - ], - ], - 'rackspace_lazy' => [ - 'type' => 'rackspace', - 'options' => [ - 'url' => 'http.xxxxx.xxx', - 'secret' => [ - 'username' => 'xxxxx', - 'password' => 'xxxxx', - 'tenant_name' => 'xxxxx', - ], - 'objectstore' => [ - 'name' => 'xxxxx', - 'region' => 'XX', - 'url_type' => 'publicURL', - 'container' => 'xxxxx', - ], - ], - ], - 'dropbox_default' => [ - 'type' => 'dropbox', - 'shared' => 'off', // optional - 'options' => [ - 'access_token' => 'xxxxx', - ], - ], - 'awss3v3_default' => [ - 'type' => 'awss3v3', - 'options' => [ - 'credentials' => [ - 'key' => 'your-app-id', - 'secret' => 'xxxxx', - ], - 'region' => 'eu-west-1', - 'bucket' => 'xxxxx', - 'version' => 'latest', // default: 'latest' - 'request.options' => [], // Guzzle request options; see http://docs.guzzlephp.org/en/latest/request-options.html#proxy - ], - ], - 'replicate_default' => [ - 'type' => 'replicate', - 'options' => [ - 'source' => 'local_default', - 'replicate' => 'zip_default', - ], - ], - 'webdav_default' => [ - 'type' => 'webdav', - 'options' => [ - 'baseUri' => 'http.xxxxx.xxx', - 'userName' => 'xxxxx', - 'password' => 'xxxxx', - ], - ], - ], - 'filesystems' => [ - 'default' => [ - 'adapter' => 'local_default', - ], - 'default_unshared' => [ - 'shared' => false, - 'adapter' => 'local_default_unshared', - ], - 'default_cached' => [ - 'adapter' => 'local_default', - 'cache' => 'Cache\BsbFlysystem\Memory', - ], - ], - 'adapter_manager' => [], - ], - 'caches' => [ - 'Cache\BsbFlysystem\Memory' => [ - 'adapter' => [ - 'name' => 'memory', - 'options' => [ - 'ttl' => 5, - 'namespace' => 'bsbflystem', - ], - ], - ], - ], - 'service_manager' => [ - 'abstract_factories' => $abstractFactories, - ], -]; diff --git a/test/Assets/bsb_flysystem.local.php b/test/Assets/bsb_flysystem.local.php new file mode 100644 index 0000000..50bb38a --- /dev/null +++ b/test/Assets/bsb_flysystem.local.php @@ -0,0 +1,234 @@ + + * @license MIT + * + * @package bushbaby/flysystem + */ + +declare(strict_types=1); + +return [ + 'bsb_flysystem' => [ + 'adapters' => [ + 'local_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\LocalAdapterFactory::class, + 'options' => [ + 'location' => './test/_build/files', + // 'visibility' => 'service_manager_key', + // 'writeFlags' => LOCK_EX, + // 'linkHandling' => self::DISALLOW_LINKS, + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'lazyRootCreation' => false, + ], + ], + 'ftp_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\FtpAdapterFactory::class, + 'options' => [ + 'connectionOptions' => [ + 'host' => 'localhost', + 'root' => '/var/www/html', + 'username' => 'username', + 'password' => '', + // 'port' => 21, + // 'ssl' => false, + // 'timeout' => 90, + // 'utf8' => false, + // 'passive' => true, + // 'transferMode' => FtpConnectionOptions::FTP_BINARY, + // 'systemType' => null, + // 'ignorePassiveAddress' => null, + // 'enableTimestampsOnUnixListings' => false, + // 'recurseManually' => false, + // 'useRawListOptions' => null, + ], + // 'connectionProvider' => 'a-connection-provider', + // 'connectivityChecker' => 'a-connectivity-checker', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibilityProvider' => 'service_manager_key', + ], + ], + 'sftp_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\SftpAdapterFactory::class, + 'options' => [ + 'connectionProvider' => [ + 'host' => 'xxxxx', + 'username' => 'xxxxx', + // 'password' => 'xxxxx', + // 'privateKey' => null, + // 'passphrase' => null, + // 'port' => 22, + // 'useAgent' => false, + // 'timeout' => 10, + // 'maxTries' => 4, + // 'hostFingerprint' => null, + // 'connectivityChecker' => 'a-connectivity-checker', + // 'preferredAlgorithms' => [], + ], + 'root' => '/var/www/html', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibilityConverter' => 'service_manager_key', + ], + ], + 'inmemory_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\InMemoryAdapterFactory::class, + 'options' => [ + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'defaultVisibility' => \League\Flysystem\Visibility::PUBLIC, + ], + ], + 'azureblobstorage_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\AzureBlobStorageAdapterFactory::class, + 'options' => [ + 'client' => [ + // @see https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ + 'connectionString' => 'DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx', + // @see MicrosoftAzure\Storage\Blob\BlobRestProxy::createBlobService + 'options' => [], + ], + 'container' => 'xxxxx', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'maxResultsForContentsListing' => 5000, + // 'visibilityHandling' => AzureBlobStorageAdapter::ON_VISIBILITY_THROW_ERROR, + // @see MicrosoftAzure\Storage\Common\Internal\StorageServiceSettings + // 'serviceSettings' => [ + // 'name' => 'xxx', + // 'key' => 'xxx', + // 'blobEndpointUri' => 'xxx', + // 'queueEndpointUri' => 'xxx', + // 'tableEndpointUri' => 'xxx', + // 'fileEndpointUri' => 'xxx', + // 'blobSecondaryEndpointUri' => null, + // 'queueSecondaryEndpointUri' => null, + // 'tableSecondaryEndpointUri' => null, + // 'fileSecondaryEndpointUri' => null, + // 'sas' => null, + // ] + ], + ], + 'googlecloudstorage_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\GoogleCloudStorageAdapterFactory::class, + 'options' => [ + 'bucket' => 'service_manager_key', // return a \Google\Cloud\Storage\Bucket + // 'prefix' => '', + // 'visibilityHandler' => 'service_manager_key', // return a \League\Flysystem\Visibility + // 'defaultVisibility' => Visibility::PRIVATE + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + ], + ], + 'zip_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\ZipArchiveAdapterFactory::class, + 'options' => [ + 'zipArchiveProvider' => [ + 'filename' => './test/_build/files.zip', + ], + 'root' => './test/_build/files', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'visibility' => 'service_manager_key', + ], + ], + 'dropbox_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\DropboxAdapterFactory::class, + 'options' => [ + 'client' => [ // or 'client' => 'service_manager_key' return a \Spatie\Dropbox\Client, + 'accessTokenOrAppCredentials' => 'xxxxx', + // 'client' => null // ClientInterface + // 'maxChunkSize' => \Spatie\Dropbox\Client::MAX_CHUNK_SIZE, + // 'maxUploadChunkRetries' => 0, + // 'teamMemberId' => null + ], + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + ], + ], + 'awss3v3_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\AwsS3v3AdapterFactory::class, + 'options' => [ + 'client' => [ + 'credentials' => [ + 'key' => 'your-app-id', + 'secret' => 'xxxxx', + ], + 'region' => 'eu-west-1', + 'bucket' => 'xxxxx', + 'version' => 'latest', // default: 'latest' + // guzzle request options; see http://docs.guzzlephp.org/en/latest/request-options.html#proxy + 'http' => [ + // 'timeout' => 10, + ], + 'use_path_style_endpoint' => true, // default: false + ], + 'bucket' => 'xxxxx', + // 'prefix' => '', + // 'mimeTypeDetector' => 'service_manager_key', // return a \League\MimeTypeDetection\MimeTypeDetector + // 'defaultVisibility' => \League\Flysystem\Visibility::PUBLIC, + // 'options' => [], + // 'streamReads' => true, + // 'forwardedOptions' => self::AVAILABLE_OPTIONS, + // 'metadataFields' => self::EXTRA_METADATA_FIELDS, + // 'multipartUploadOptions' => self::MUP_AVAILABLE_OPTIONS, + ], + ], + 'replicate_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\ReplicateAdapterFactory::class, + 'options' => [ + 'source' => 'local_default', + 'replica' => 'zip_default', + ], + ], + 'webdav_default' => [ + 'factory' => BsbFlysystem\Adapter\Factory\WebDAVAdapterFactory::class, + 'options' => [ + 'client' => [ + 'baseUri' => 'https://example.org/remote.php/webdav/', + // 'userName' => '', + // 'password' => '', + // 'proxy' => '', + // 'authType' => '', + // 'encoding' => '', + ], + // 'prefix' => '', + // 'visibilityHandling' => WebDAVAdapter::ON_VISIBILITY_THROW_ERROR, + // 'manualCopy' => false, + // 'manualMove' => false, + ], + ], + ], + 'filesystems' => [ + 'default' => [ + 'adapter' => 'local_default', + 'adapter_options' => null, + 'options' => [ + 'pathNormalizer' => null, // returns PathNormalizer::class + 'publicUrlGenerator' => null, // returns \League\Flysystem\UrlGeneration\PublicUrlGeneratorInterface::class + 'temporaryUrlGenerator' => null, // returns \League\Flysystem\UrlGeneration\TemporaryUrlGenerator::class + ], + ], + ], + 'adapter_manager' => [ + 'config' => [], + 'lazy_services' => [ + // directory where proxy classes will be written - default to system_get_tmp_dir() + // 'proxies_target_dir' => 'data/cache', + // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy" + // 'proxies_namespace' => null, + // whether the generated proxy classes should be written to disk + // 'write_proxy_files' => false, + ], + ], + 'filesystem_manager' => [ + 'config' => [], + ], + ], +]; diff --git a/test/Bootstrap.php b/test/Bootstrap.php index 40176f2..5b6b290 100644 --- a/test/Bootstrap.php +++ b/test/Bootstrap.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,7 +22,6 @@ use Laminas\Mvc\Service\ServiceManagerConfig; use Laminas\ServiceManager\ServiceManager; use Psr\Container\ContainerInterface; -use RuntimeException; class Bootstrap { @@ -57,7 +56,7 @@ protected static function initAutoloader(): void return; } - throw new RuntimeException('Unable to load Laminas. Run `php composer.phar install` or define a LAMINAS_PATH environment variable.'); + throw new \RuntimeException('Unable to load Laminas. Run `php composer.phar install` or define a LAMINAS_PATH environment variable.'); } public static function getApplicationConfig(): array diff --git a/test/Cache/ZendStorageCacheTest.php b/test/Cache/ZendStorageCacheTest.php deleted file mode 100644 index 17bb16f..0000000 --- a/test/Cache/ZendStorageCacheTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license MIT - * - * @package bushbaby/flysystem - */ - -declare(strict_types=1); - -namespace BsbFlysystemTest\Cache; - -use BsbFlysystem\Cache\ZendStorageCache; -use PHPUnit\Framework\TestCase; - -class ZendStorageCacheTest extends TestCase -{ - protected function setUp(): void - { - if (! class_exists('Laminas\Cache\Storage\StorageInterface')) { - $this->markTestSkipped('laminas/laminas-cache not required'); - } - } - - public function testLoadDefault(): void - { - $mock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - $mock->expects($this->once())->method('getItem'); - - $zendStorageCache = new ZendStorageCache($mock); - $zendStorageCache->load(); - } - - public function testLoadDefaultCallsSetFromStorage(): void - { - $mock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - // setFromStorage expects json in this form - $mock->expects($this->once())->method('getItem')->willReturn('this-is-not-valid-json'); - - $zendStorageCache = new ZendStorageCache($mock); - $zendStorageCache->load(); - - $this->assertTrue(JSON_ERROR_NONE !== json_last_error()); - } - - public function testLoadWithCustomKey(): void - { - $mock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - $mock->expects($this->once())->method('getItem')->with('akey'); - $zendStorageCache = new ZendStorageCache($mock, 'akey'); - - $zendStorageCache->load(); - } - - public function testSaveDefault(): void - { - $mock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - $mock->expects($this->once())->method('setItem'); - - $zendStorageCache = new ZendStorageCache($mock); - $zendStorageCache->save(); - } - - public function testSaveWithCustomKey(): void - { - $mock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - $mock->expects($this->once())->method('setItem')->with('akey'); - - $zendStorageCache = new ZendStorageCache($mock, 'akey'); - $zendStorageCache->save(); - } -} diff --git a/test/ConfigProviderTest.php b/test/ConfigProviderTest.php index a064f68..c7ba485 100644 --- a/test/ConfigProviderTest.php +++ b/test/ConfigProviderTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * diff --git a/test/Exception/RequirementsExceptionTest.php b/test/Exception/RequirementsExceptionTest.php index 46bbccc..41a491e 100644 --- a/test/Exception/RequirementsExceptionTest.php +++ b/test/Exception/RequirementsExceptionTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * diff --git a/test/Filesystem/Factory/FilesystemFactoryTest.php b/test/Filesystem/Factory/FilesystemFactoryTest.php index bd34884..a0cad68 100644 --- a/test/Filesystem/Factory/FilesystemFactoryTest.php +++ b/test/Filesystem/Factory/FilesystemFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -19,138 +19,45 @@ namespace BsbFlysystemTest\Filesystem\Factory; -use BsbFlysystem\Cache\ZendStorageCache; -use BsbFlysystem\Exception\UnexpectedValueException; use BsbFlysystem\Filesystem\Factory\FilesystemFactory; +use BsbFlysystem\Service\AdapterManager; use Interop\Container\ContainerInterface; -use League\Flysystem\Adapter\NullAdapter; -use League\Flysystem\Cached\CachedAdapter; -use League\Flysystem\Cached\CacheInterface; -use League\Flysystem\EventableFilesystem\EventableFilesystem; use League\Flysystem\Filesystem; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use PHPUnit\Framework\TestCase; -use ReflectionClass; +use Prophecy\Prophet; class FilesystemFactoryTest extends TestCase { - public function testThrowsExceptionForMissingAdapter(): void - { - $factory = new FilesystemFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'filesystems' => [ - 'named_fs' => [], - ], - ], - ]; - - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); + protected Prophet $prophet; - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage("Missing 'adapter' key for the filesystem 'named_fs' configuration"); - - $factory($serviceLocatorMock, 'named_fs'); - } - - public function testCreateServiceWithNameReturnsFilesystem(): void + protected function setUp(): void { - $factory = new FilesystemFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'filesystems' => [ - 'named_fs' => [ - 'adapter' => 'named_adapter', - ], - ], - ], - ]; - - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); - - $adapter = new NullAdapter(); - $adapterPluginMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(1))->method('get')->with('BsbFlysystemAdapterManager')->willReturn($adapterPluginMock); - $adapterPluginMock->expects($this->once())->method('get')->with('named_adapter')->willReturn($adapter); - - $service = $factory($serviceLocatorMock, 'named_fs'); - - $this->assertInstanceOf(FilesystemInterface::class, $service); - $this->assertInstanceOf(Filesystem::class, $service); - $this->assertNotInstanceOf(EventableFilesystem::class, $service); + $this->prophet = new Prophet(); } - public function testCreateServiceWithNameReturnsEventableFilesystem(): void + protected function tearDown(): void { - $factory = new FilesystemFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'filesystems' => [ - 'named_fs' => [ - 'adapter' => 'named_adapter', - 'eventable' => true, - ], - ], - ], - ]; - - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); - - $adapter = new NullAdapter(); - $adapterPluginMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(1))->method('get')->with('BsbFlysystemAdapterManager')->willReturn($adapterPluginMock); - $adapterPluginMock->expects($this->once())->method('get')->with('named_adapter')->willReturn($adapter); - - $service = $factory($serviceLocatorMock, 'named_fs'); - - $this->assertInstanceOf(FilesystemInterface::class, $service); - $this->assertInstanceOf(EventableFilesystem::class, $service); + $this->prophet->checkPredictions(); } - public function testCreateServiceWithNameCachedAdapter(): void + public function testConfigMissingAdapterName(): void { - $factory = new FilesystemFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'filesystems' => [ - 'named_fs' => [ - 'adapter' => 'named_adapter', - 'cache' => 'named/cache', - ], + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ + 'bsb_flysystem' => [ + 'filesystems' => ['not-an-array'], ], - ], - ]; + ]); - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); + $this->expectException(\AssertionError::class); - $adapter = new NullAdapter(); - $adapterPluginMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(1))->method('get')->with('BsbFlysystemAdapterManager')->willReturn($adapterPluginMock); - $adapterPluginMock->expects($this->once())->method('get')->with('named_adapter')->willReturn($adapter); - - $cacheMock = $this->getMockBuilder(CacheInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(2))->method('get')->with('named/cache')->willReturn($cacheMock); - - /** @var Filesystem $service */ - $service = $factory($serviceLocatorMock, 'named_fs'); - - $this->assertInstanceOf(CachedAdapter::class, $service->getAdapter()); + (new FilesystemFactory())($container->reveal(), 'named_fs'); } - public function testCreateServiceWithNameCachedAdapterLaminasCacheStorage(): void + public function testCreateServiceWithNameReturnsFilesystem(): void { - if (! class_exists('Laminas\Cache\Service\StorageCacheAbstractServiceFactory')) { - $this->markTestSkipped('laminas/laminas-cache not required'); - } - $factory = new FilesystemFactory(); $config = [ @@ -158,64 +65,24 @@ public function testCreateServiceWithNameCachedAdapterLaminasCacheStorage(): voi 'filesystems' => [ 'named_fs' => [ 'adapter' => 'named_adapter', - 'cache' => 'named/cache', ], ], ], ]; - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); + $container = $this->prophet->prophesize(ContainerInterface::class); + $adapterManager = $this->prophet->prophesize(AdapterManager::class); - $adapter = new NullAdapter(); - $adapterPluginMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(1))->method('get')->with('BsbFlysystemAdapterManager')->willReturn($adapterPluginMock); - $adapterPluginMock->expects($this->once())->method('get')->with('named_adapter')->willReturn($adapter); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn($config); - $cacheMock = $this->getMockBuilder('Laminas\Cache\Storage\StorageInterface')->getMock(); - $serviceLocatorMock->expects($this->at(2))->method('get')->with('named/cache')->willReturn($cacheMock); + $adapter = new InMemoryFilesystemAdapter(); - /** @var Filesystem $service */ - $service = $factory($serviceLocatorMock, 'named_fs'); + $adapterManager->get('named_adapter', null)->willReturn($adapter); + $container->get(AdapterManager::class)->willReturn($adapterManager->reveal()); - $this->assertInstanceOf(CachedAdapter::class, $service->getAdapter()); + $service = $factory($container->reveal(), 'named_fs'); - $class = new ReflectionClass(CachedAdapter::class); - $property = $class->getProperty('cache'); - $property->setAccessible(true); - - $cacheInstance = $property->getValue($service->getAdapter()); - $this->assertInstanceOf(ZendStorageCache::class, $cacheInstance); - } - - public function testCreateServiceWithNameReturnsFilesystemWithPluginsAdded(): void - { - $factory = new FilesystemFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'filesystems' => [ - 'named_fs' => [ - 'adapter' => 'named_adapter', - 'plugins' => [ - 'League\Flysystem\Plugin\ListPaths', - ], - ], - ], - ], - ]; - - $serviceLocatorMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(0))->method('get')->with('config')->willReturn($config); - - $adapter = new NullAdapter(); - $adapterPluginMock = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $serviceLocatorMock->expects($this->at(1))->method('get')->with('BsbFlysystemAdapterManager')->willReturn($adapterPluginMock); - $adapterPluginMock->expects($this->once())->method('get')->with('named_adapter')->willReturn($adapter); - - $service = $factory($serviceLocatorMock, 'named_fs'); - - // works because plugin is registered - $this->assertEmpty($service->listPaths()); + $this->assertInstanceOf(Filesystem::class, $service); } } diff --git a/test/Filter/File/RenameUploadTest.php b/test/Filter/File/RenameUploadTest.php index 3f7f9c9..885d6b9 100644 --- a/test/Filter/File/RenameUploadTest.php +++ b/test/Filter/File/RenameUploadTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,37 +22,41 @@ use BsbFlysystem\Filter\File\RenameUpload; use Laminas\Filter\Exception\InvalidArgumentException; use Laminas\Filter\Exception\RuntimeException; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\Filesystem; +use League\Flysystem\UnableToWriteFile; use PHPUnit\Framework\TestCase; use Prophecy\Argument; -use UnexpectedValueException; +use Prophecy\Prophet; require_once __DIR__ . '/../../Assets/Functions.php'; class RenameUploadTest extends TestCase { - /** - * @var FilesystemInterface - */ - protected $filesystem; + protected Prophet $prophet; - public function setup(): void + protected function setUp(): void { - $this->filesystem = $this->prophesize(FilesystemInterface::class); + $this->prophet = new Prophet(); + } + + protected function tearDown(): void + { + $this->prophet->checkPredictions(); } public function testCanUploadFile(): void { $path = 'path/to/file.txt'; - $this->filesystem->putStream($path, Argument::any()) - ->willReturn(true) - ->shouldBeCalled(); - $this->filesystem->has($path) + + $filesystem = $this->prophet->prophesize(Filesystem::class); + $filesystem->writeStream($path, Argument::any()); + + $filesystem->has($path) ->willReturn(false); $filter = new RenameUpload([ 'target' => $path, - 'filesystem' => $this->filesystem->reveal(), + 'filesystem' => $filesystem->reveal(), ]); $key = $filter->filter(__DIR__ . '/../../Assets/test.txt'); @@ -62,15 +66,14 @@ public function testCanUploadFile(): void public function testCanUploadFileWhenUploading(): void { $path = 'path/to/file.txt'; - $this->filesystem->putStream($path, Argument::any()) - ->willReturn(true) - ->shouldBeCalled(); - $this->filesystem->has($path) - ->willReturn(false); + $filesystem = $this->prophet->prophesize(Filesystem::class); + + $filesystem->writeStream($path, Argument::any()); + $filesystem->has($path)->willReturn(false); $filter = new RenameUpload([ 'target' => $path, - 'filesystem' => $this->filesystem->reveal(), + 'filesystem' => $filesystem->reveal(), ]); $file = [ @@ -88,19 +91,19 @@ public function testWillThrowExceptionWhenFilesystemNotSet(): void 'target' => 'path/to/file.txt', ]); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $filter->filter(__DIR__ . '/../../Assets/test.txt'); } public function testWillThrowExceptionWhenFileIsNotPostUploaded(): void { $path = 'path/to/file.txt'; - $this->filesystem->has($path) - ->willReturn(false); + $filesystem = $this->prophet->prophesize(Filesystem::class); + $filesystem->has($path)->willReturn(false); $filter = new RenameUpload([ 'target' => $path, - 'filesystem' => $this->filesystem->reveal(), + 'filesystem' => $filesystem->reveal(), ]); $this->expectException(RuntimeException::class); @@ -111,33 +114,31 @@ public function testWillThrowExceptionWhenFileIsNotPostUploaded(): void public function testWillThrowExceptionWhenFileExists(): void { $path = 'path/to/file.txt'; - $this->filesystem->has($path) - ->willReturn(true) - ->shouldBeCalled(); + $filesystem = $this->prophet->prophesize(Filesystem::class); + $filesystem->has($path)->willReturn(true); $filter = new RenameUpload([ 'target' => $path, 'overwrite' => false, - 'filesystem' => $this->filesystem->reveal(), + 'filesystem' => $filesystem->reveal(), ]); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage("File 'path/to/file.txt' could not be uploaded. It already exists."); + $filter->filter(__DIR__ . '/../../Assets/test.txt'); } public function testWillThrowExceptionWhenFilesystemFails(): void { $path = 'path/to/file.txt'; - $this->filesystem->putStream($path, Argument::any()) - ->willReturn(false) - ->shouldBeCalled(); - $this->filesystem->has($path) - ->willReturn(false); + $filesystem = $this->prophet->prophesize(Filesystem::class); + $filesystem->writeStream($path, Argument::any())->willThrow(UnableToWriteFile::class); + $filesystem->has($path)->willReturn(false); $filter = new RenameUpload([ 'target' => $path, - 'filesystem' => $this->filesystem->reveal(), + 'filesystem' => $filesystem->reveal(), ]); $this->expectException(RuntimeException::class); @@ -145,6 +146,7 @@ public function testWillThrowExceptionWhenFilesystemFails(): void "File '%s' could not be uploaded. An error occurred while processing the file.", __DIR__ . '/../../Assets/test.txt' )); + $filter->filter(__DIR__ . '/../../Assets/test.txt'); } } diff --git a/test/ModuleTest.php b/test/ModuleTest.php index 042f2ab..124010e 100644 --- a/test/ModuleTest.php +++ b/test/ModuleTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * diff --git a/test/Services/AdapterManagerTest.php b/test/Services/AdapterManagerTest.php index dd8e213..a72a265 100644 --- a/test/Services/AdapterManagerTest.php +++ b/test/Services/AdapterManagerTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -23,8 +23,9 @@ use BsbFlysystem\Service\AdapterManager; use BsbFlysystemTest\Bootstrap; use Laminas\ServiceManager\ServiceManager; +use League\Flysystem\PathPrefixing\PathPrefixedAdapter; +use League\Flysystem\ReadOnly\ReadOnlyFilesystemAdapter; use PHPUnit\Framework\TestCase; -use stdClass; class AdapterManagerTest extends TestCase { @@ -47,7 +48,7 @@ public function testCreateByAliasViaServiceManager(): void public function testManagerValidatesPlugin(): void { $manager = new AdapterManager(new ServiceManager()); - $plugin = $this->getMockBuilder(\League\Flysystem\Adapter\AbstractAdapter::class) + $plugin = $this->getMockBuilder(\League\Flysystem\FilesystemAdapter::class) ->disableOriginalConstructor() ->getMock(); @@ -55,23 +56,31 @@ public function testManagerValidatesPlugin(): void $this->expectException(RuntimeException::class); - $plugin = new stdClass(); + $plugin = new \stdClass(); $manager->validatePlugin($plugin); } public function testCreateViaServiceManagerLocal(): void { $sm = Bootstrap::getServiceManager(); - $manager = $sm->get('BsbFlysystemAdapterManager'); + $manager = $sm->get(AdapterManager::class); - $this->assertInstanceOf(\League\Flysystem\Adapter\AbstractAdapter::class, $manager->get('local_default')); + $this->assertInstanceOf(\League\Flysystem\FilesystemAdapter::class, $manager->get('local_default')); } - public function testCreateViaServiceManagerNull(): void + public function testWrapsPathPrefixedAdapter(): void { $sm = Bootstrap::getServiceManager(); - $manager = $sm->get(AdapterManager::class); + $adapter = $sm->get(AdapterManager::class)->get('local_default', ['prefix' => '/path']); + + $this->assertInstanceOf(PathPrefixedAdapter::class, $adapter); + } + + public function testWrapsReadOnlyFilesystemAdapter(): void + { + $sm = Bootstrap::getServiceManager(); + $adapter = $sm->get(AdapterManager::class)->get('local_default', ['readonly' => true]); - $this->assertInstanceOf(\League\Flysystem\Adapter\NullAdapter::class, $manager->get('null_default')); + $this->assertInstanceOf(ReadOnlyFilesystemAdapter::class, $adapter); } } diff --git a/test/Services/Factory/AdapterManagerFactoryTest.php b/test/Services/Factory/AdapterManagerFactoryTest.php index a8eac24..5c57744 100644 --- a/test/Services/Factory/AdapterManagerFactoryTest.php +++ b/test/Services/Factory/AdapterManagerFactoryTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -22,94 +22,54 @@ use BsbFlysystem\Service\AdapterManager; use BsbFlysystem\Service\Factory\AdapterManagerFactory; use PHPUnit\Framework\TestCase; +use Prophecy\Prophet; +use Psr\Container\ContainerInterface; class AdapterManagerFactoryTest extends TestCase { - public function testCreateService(): void - { - $factory = new AdapterManagerFactory(); - - $config = [ - 'bsb_flysystem' => [ - 'adapters' => [], - ], - ]; + protected Prophet $prophet; - $serviceLocatorMock = $this->getMockBuilder('Interop\Container\ContainerInterface')->getMock(); - $serviceLocatorMock->expects($this->once())->method('get')->with('config')->willReturn($config); - - $this->assertInstanceOf('BsbFlysystem\Service\AdapterManager', $factory($serviceLocatorMock, null)); + protected function setUp(): void + { + $this->prophet = new Prophet(); } - public function testServicesSharedByDefault(): void + protected function tearDown(): void { - $factory = new AdapterManagerFactory(); - $config = [ - 'bsb_flysystem' => [ - 'adapters' => [ - 'named_adapter' => [ - 'type' => 'someadapter', - 'shared' => true, - ], - ], - 'adapter_map' => [ - 'factories' => [ - 'someadapter' => 'Laminas\ServiceManager\Factory\InvokableFactory', - ], - 'aliases' => [ - 'someadapter' => 'Some/Adapter', - ], - ], - ], - ]; - - $serviceLocatorMock = $this->getMockBuilder('Interop\Container\ContainerInterface')->getMock(); - $serviceLocatorMock->expects($this->once())->method('get')->with('config')->willReturn($config); - - /** @var AdapterManager $adapterManager */ - $adapterManager = $factory($serviceLocatorMock, null); + $this->prophet->checkPredictions(); } - public function testThrowsExceptionForMissingAdapterType(): void + public function testCreateService(): void { - $factory = new AdapterManagerFactory(); - - $config = [ + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ 'bsb_flysystem' => [ 'adapters' => [ - 'named_adapter' => [], ], ], - ]; + ]); - $serviceLocatorMock = $this->getMockBuilder('Interop\Container\ContainerInterface')->getMock(); - $serviceLocatorMock->expects($this->once())->method('get')->with('config')->willReturn($config); + $adapterManager = (new AdapterManagerFactory())($container->reveal(), null); - $this->expectException( - 'UnexpectedValueException', - "Missing 'type' key for the adapter 'named_adapter' configuration" - ); - $factory($serviceLocatorMock, null); + $this->assertInstanceOf(AdapterManager::class, $adapterManager); } - public function testThrowsExceptionForUnknownAdapterType(): void + public function testThrowsExceptionForMissingAdapterFactory(): void { - $factory = new AdapterManagerFactory(); - - $config = [ + $container = $this->prophet->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ 'bsb_flysystem' => [ 'adapters' => [ - 'named_adapter' => [ - 'type' => 'unknown_adapter', - ], + 'named_adapter' => [], ], ], - ]; + ]); - $serviceLocatorMock = $this->getMockBuilder('Interop\Container\ContainerInterface')->getMock(); - $serviceLocatorMock->expects($this->once())->method('get')->with('config')->willReturn($config); + $this->expectException(\AssertionError::class); + $this->expectExceptionMessage("Option 'factory' must be defined in an adapter configuration"); - $this->expectException('BsbFlysystem\Exception\UnexpectedValueException'); - $factory($serviceLocatorMock, null); + (new AdapterManagerFactory())($container->reveal(), null); } } diff --git a/test/Services/FilesystemManagerTest.php b/test/Services/FilesystemManagerTest.php index 323cdf7..7921273 100644 --- a/test/Services/FilesystemManagerTest.php +++ b/test/Services/FilesystemManagerTest.php @@ -8,7 +8,7 @@ * * @see https://bushbaby.nl/ * - * @copyright Copyright (c) 2014-2021 bushbaby multimedia. (https://bushbaby.nl) + * @copyright Copyright (c) 2014 bushbaby multimedia. (https://bushbaby.nl) * @author Bas Kamer * @license MIT * @@ -21,14 +21,9 @@ use BsbFlysystem\Service\FilesystemManager; use BsbFlysystemTest\Bootstrap; -use Laminas\ServiceManager\AbstractPluginManager; use Laminas\ServiceManager\ServiceManager; -use League\Flysystem\Adapter\AbstractAdapter; -use League\Flysystem\Cached\CachedAdapter; use League\Flysystem\Filesystem; -use League\Flysystem\FilesystemInterface; use PHPUnit\Framework\TestCase; -use stdClass; class FilesystemManagerTest extends TestCase { @@ -51,7 +46,7 @@ public function testCreateByAliasViaServiceManager(): void public function testManagerValidatesPlugin(): void { $manager = new FilesystemManager(new ServiceManager()); - $plugin = $this->getMockBuilder(FilesystemInterface::class) + $plugin = $this->getMockBuilder(Filesystem::class) ->disableOriginalConstructor() ->getMock(); @@ -59,7 +54,7 @@ public function testManagerValidatesPlugin(): void $this->expectException('RuntimeException'); - $plugin = new stdClass(); + $plugin = new \stdClass(); $manager->validatePlugin($plugin); } @@ -68,69 +63,41 @@ public function testCanGetSpecificFilesystem(): void $sm = Bootstrap::getServiceManager(); $manager = $sm->get('BsbFlysystemManager'); - $this->assertInstanceOf(FilesystemInterface::class, $manager->get('default')); + $this->assertInstanceOf(Filesystem::class, $manager->get('default')); } public function testServicesSharedByDefault(): void { $sm = Bootstrap::getServiceManager(); - /** @var AbstractPluginManager $manager */ + + /** @var FilesystemManager $manager */ $manager = $sm->get(FilesystemManager::class); $localA = $manager->get('default'); $localB = $manager->get('default'); - $this->assertTrue($localA === $localB); + $this->assertSame($localA, $localB); } public function testConfigurationOverrideableForNotSharedServices(): void { $sm = Bootstrap::getServiceManager(); + /** @var FilesystemManager $manager */ $manager = $sm->get(FilesystemManager::class); /** @var Filesystem $filesystem */ - $filesystem = $manager->get('default_unshared'); - - /** @var AbstractAdapter $adapter */ - $adapter = $filesystem->getAdapter(); - - $pathPrefix = $adapter->getPathPrefix(); - $pathPrefix = str_replace(realpath('.'), '', $pathPrefix); - - $this->assertEquals('./test/_build/files/', $pathPrefix); - - /** @var Filesystem $filesystem */ - $filesystem = $manager->get( - 'default_unshared', - ['adapter_options' => ['root' => './test/_build/documents']] - ); - - /** @var AbstractAdapter $adapter */ - $adapter = $filesystem->getAdapter(); - - $pathPrefix = $adapter->getPathPrefix(); - $pathPrefix = str_replace(realpath('.'), '', $pathPrefix); - - $this->assertEquals('./test/_build/documents/', $pathPrefix); - } - - public function testCanGetCachedFilesystem(): void - { - if (! class_exists('Laminas\Cache\Service\StorageCacheAbstractServiceFactory')) { - $this->markTestSkipped('laminas/laminas-cache not required'); - } - - $sm = Bootstrap::getServiceManager(); - - /** @var FilesystemManager $manager */ - $manager = $sm->get(FilesystemManager::class); + $localA = $manager->get('default'); /** @var Filesystem $filesystem */ - $filesystem = $manager->get('default_cached'); + $localB = $manager->get('default', [ + 'adapter_options' => ['location' => './test/_build/documents'], + ]); - /** @var CachedAdapter $adapter */ - $adapter = $filesystem->getAdapter(); + $localA->write('/test-from-fs1.txt', ''); + $localB->write('/test-from-fs2.txt', ''); - $this->assertInstanceOf(CachedAdapter::class, $adapter); + $this->assertNotSame($localA, $localB); + $this->assertFalse($localA->has('/test-from-fs2.txt')); + $this->assertFalse($localB->has('/test-from-fs1.txt')); } } diff --git a/test/TestConfiguration.php.dist b/test/TestConfiguration.php.dist index 1b3641c..3e3ca78 100644 --- a/test/TestConfiguration.php.dist +++ b/test/TestConfiguration.php.dist @@ -6,8 +6,8 @@ return [ ], 'module_listener_options' => [ 'config_glob_paths' => [ - __DIR__ . '/Assets/bsb_flysystem.global.php', + __DIR__ . '/Assets/bsb_flysystem.local.php', ], 'module_paths' => [] ], -]; \ No newline at end of file +];