├── .gitignore ├── .styleci.yml ├── .travis.yml ├── .editorconfig ├── .php_cs ├── phpunit.xml ├── composer.json ├── LICENSE.md ├── src ├── SelectelServiceProvider.php └── SelectelAdapter.php ├── CONTRIBUTING.md ├── CHANGELOG.md ├── README.md └── tests └── SelectelAdapterTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /dev/ 3 | /vendor/ 4 | composer.lock 5 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | finder: 3 | path: 4 | - "src" 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 7.0 5 | - 7.1 6 | sudo: false 7 | before_install: 8 | - composer self-update 9 | - composer install --no-interaction --prefer-dist --no-suggest 10 | script: 11 | - vendor/bin/phpunit 12 | notifications: 13 | email: 14 | on_success: never 15 | on_failure: always 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_size = 4 10 | indent_style = space 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | in(__DIR__.'/src'); 4 | 5 | return PhpCsFixer\Config::create() 6 | ->setUsingCache(false) 7 | ->setRules([ 8 | '@PSR2' => true, 9 | 'phpdoc_align' => true, 10 | 'phpdoc_no_empty_return' => true, 11 | 'phpdoc_order' => true, 12 | 'phpdoc_separation' => true, 13 | 'array_syntax' => ['syntax' => 'short'], 14 | 'no_unused_imports' => true, 15 | 'phpdoc_trim' => true, 16 | ]) 17 | ->setFinder($finder); 18 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests 14 | 15 | 16 | 17 | 18 | ./src 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "argentcrusade/flysystem-selectel", 3 | "description": "Flysystem adapter for Selectel Cloud Storage", 4 | "keywords": ["flysystem", "selectel"], 5 | "homepage": "https://github.com/argentcrusade/flysystem-selectel", 6 | "license": "MIT", 7 | "require": { 8 | "php": ">=5.6", 9 | "league/flysystem": "~1.0", 10 | "argentcrusade/selectel-cloud-storage": "~1.1" 11 | }, 12 | "require-dev": { 13 | "phpunit/phpunit": "~5.0", 14 | "mockery/mockery": "~0.9" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "ArgentCrusade\\Flysystem\\Selectel\\": "src/" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "classmap": [ 23 | "tests/" 24 | ] 25 | }, 26 | "extra": { 27 | "laravel": { 28 | "providers": [ 29 | "ArgentCrusade\\Flysystem\\Selectel\\SelectelServiceProvider" 30 | ] 31 | } 32 | }, 33 | "scripts": { 34 | "test": "phpunit" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 tzurbaev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/SelectelServiceProvider.php: -------------------------------------------------------------------------------- 1 | authenticate(); 21 | 22 | $storage = new CloudStorage($api); 23 | $container = $storage->getContainer($config['container']); 24 | 25 | if (isset($config['container_url'])) { 26 | $container->setUrl($config['container_url']); 27 | } 28 | 29 | return new Filesystem(new SelectelAdapter($container)); 30 | }); 31 | } 32 | 33 | /** 34 | * Register the application services. 35 | */ 36 | public function register() 37 | { 38 | // 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/ArgentCrusade/flysystem-selectel). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Check the code style with ``$ php-cs-fixer fix --dry-run --diff`` and fix it with ``$ php-cs-fixer fix``. See **[PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)** repository for more info. 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ vendor/bin/phpunit 29 | ``` 30 | 31 | **Happy coding**! 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.2.0] - 2017-09-27 10 | ### Added 11 | - Added support for Laravel 5.5.'s auto-discovery feature (thanks @reg2005). 12 | 13 | ## [1.1.2] - 2017-07-26 14 | ### Added 15 | - Add `mimetype` field to transformed files array, allowing to use Flysystem's `getMimetype` method. 16 | 17 | ## [1.1.1] - 2017-04-18 18 | ### Changed 19 | - Perform API authentication in SelectelServiceProvider. 20 | 21 | ## [1.1.0] - 2017-04-18 22 | ### Added 23 | - New configuration option `container_url`. This will help you to retrieve file URLs while using custom CDN domain; 24 | - `SelectelAdapter::getUrl` method to retrieve full URL to given file/directory path. This will allow Laravel to use File URLs just like with `s3` adapter. 25 | 26 | ## [1.0.1] - 2017-03-11 27 | ### Added 28 | - Built-in Service Provider for Laravel Framework; 29 | - Information about Flysystem methods that are not supported by this adapter. 30 | 31 | ## [1.0.0] - 2017-03-11 32 | First release. 33 | 34 | ### Added 35 | - Laravel Integration docs. 36 | 37 | ### Fixed 38 | - Directories are marked as `dir` in content listings; 39 | - Fixed issue with single file retrieving; 40 | - Fixed issue with file/directory sizes detection. 41 | 42 | ### Removed 43 | - Visibility support. 44 | 45 | ## [0.9.0] - 2017-03-11 46 | Initial release. 47 | 48 | [Unreleased]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.2.0...HEAD 49 | [1.2.0]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.1.2...1.2.0 50 | [1.1.2]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.1.1...1.1.2 51 | [1.1.1]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.1.0...1.1.1 52 | [1.1.0]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.0.1...1.1.0 53 | [1.0.1]: https://github.com/ArgentCrusade/flysystem-selectel/compare/1.0.0...1.0.1 54 | [1.0.0]: https://github.com/ArgentCrusade/flysystem-selectel/compare/0.9.0...1.0.0 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flysystem Adapter for Selectel Cloud Storage 2 | 3 | [![Build Status][ico-travis]][link-travis] 4 | [![StyleCI][ico-styleci]][link-styleci] 5 | [![ScrutinizerCI][ico-scrutinizer]][link-scrutinizer] 6 | [![Latest Version on Packagist][ico-version]][link-packagist] 7 | [![Software License][ico-license]](LICENSE.md) 8 | 9 | ## Requirements 10 | This package requires PHP 5.6 or higher. 11 | 12 | ## Installation 13 | 14 | You can install the package via composer: 15 | 16 | ``` bash 17 | $ composer require argentcrusade/flysystem-selectel 18 | ``` 19 | 20 | ## Upgrade 21 | 22 | ### From 1.0* to 1.1.0 23 | New setting `container_url` was added. You can set your container's custom domain here (for example, `https://static.example.org`) and this option will be used when retrieving fully qualified URLs to files and directories. 24 | 25 | ## Usage 26 | 27 | ``` php 28 | use ArgentCrusade\Flysystem\Selectel\SelectelAdapter; 29 | use ArgentCrusade\Selectel\CloudStorage\Api\ApiClient; 30 | use ArgentCrusade\Selectel\CloudStorage\CloudStorage; 31 | use League\Flysystem\Filesystem; 32 | 33 | $api = new ApiClient('selectel-username', 'selectel-password'); 34 | $storage = new CloudStorage($api); 35 | $container = $storage->getContainer('container-name'); 36 | 37 | $adapter = new SelectelAdapter($container); 38 | $filesystem = new Filesystem($adapter); 39 | ``` 40 | 41 | ## Laravel Integration 42 | 43 | You can use this adapter with Laravel's [Storage System](https://laravel.com/docs/5.5/filesystem). 44 | 45 | If you're running Laravel 5.5+ this package will auto-added to your providers list via auto-discovery feature (requires version 1.2+ of this package). 46 | 47 | ### Laravel <= 5.4 48 | Add `ArgentCrusade\Flysystem\Selectel\SelectelServiceProvider::class` to your providers list in `config/app.php` 49 | 50 | ```php 51 | /* 52 | * Package Service Providers... 53 | */ 54 | ArgentCrusade\Flysystem\Selectel\SelectelServiceProvider::class, 55 | ``` 56 | 57 | ### All Laravel versions 58 | Add `selectel` disk to `config/filesystems.php` configuration file (`disks` section): 59 | 60 | ```php 61 | 'selectel' => [ 62 | 'driver' => 'selectel', 63 | 'username' => 'selectel-username', 64 | 'password' => 'selectel-password', 65 | 'container' => 'selectel-container', 66 | 'container_url' => 'https://static.example.org', 67 | ] 68 | ``` 69 | 70 | `container_url` setting (new in version **1.1.0**) allows you to override default Selectel's CDN domain (if you have custom domain attached). You may omit this setting if you're using default domain, file URLs will look like `http://XXX.selcdn.ru/container_name/path/to/file.txt`, where `XXX` - your unique subdomain (`X-Storage-Url` header value). 71 | 72 | Now you can use Selectel disk as 73 | 74 | ```php 75 | use Illuminate\Support\Facades\Storage; 76 | 77 | Storage::disk('selectel')->put('file.txt', 'Hello world'); 78 | ``` 79 | 80 | Also you may want to set `selectel` as default disk to ommit `disk('selectel')` calls and use storage just as `Storage::put('file.txt', 'Hello world')`. 81 | 82 | For more info please refer to Laravel's [Storage System](https://laravel.com/docs/5.4/filesystem) documentation. 83 | 84 | ## Unsupported methods 85 | Due to the implementation of the Selectel API some methods are missing or may not function as expected. 86 | 87 | ### Visibility management 88 | Selectel provides visibility support only for Containers, but not for files. The change of visibility for the entire container instead of a single file/directory may be confusing for adapter users. Adapter will throw `LogicException` on `getVisibility`/`setVisbility` calls. 89 | 90 | ### Directories management 91 | Currently Selectel Adapter can display and delete only those directories that were created via `createDir` method. Dynamic directories (those that were created via `write`/`writeStream` methods) can not be deleted or listed as directory. 92 | 93 | ```php 94 | $fs = new Filesystem($adapter); 95 | 96 | $fs->createDir('images'); // The 'images' directory can be deleted and will be listed as 'dir' in the results of `$fs->listContents()`. 97 | 98 | $fs->write('documents/hello.txt'); // The 'documents' directory can not be deleted and won't be listed in the results of `$fs->listContents()`. 99 | ``` 100 | 101 | ## Note on Closing Streams 102 | Selectel Adapter leaves the streams **open** after consuming them. Make sure that you've closed all streams that you opened. 103 | 104 | ## Change log 105 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 106 | 107 | ## Testing 108 | ``` bash 109 | $ vendor/bin/phpunit 110 | ``` 111 | 112 | ## Contributing 113 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 114 | 115 | ## Security 116 | If you discover any security related issues, please email zurbaev@gmail.com instead of using the issue tracker. 117 | 118 | ## License 119 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 120 | 121 | [ico-version]: https://poser.pugx.org/argentcrusade/flysystem-selectel/version?format=flat 122 | [ico-license]: https://poser.pugx.org/argentcrusade/flysystem-selectel/license?format=flat 123 | [ico-travis]: https://api.travis-ci.org/ArgentCrusade/flysystem-selectel.svg?branch=master 124 | [ico-styleci]: https://styleci.io/repos/84637792/shield?branch=master&style=flat 125 | [ico-scrutinizer]: https://scrutinizer-ci.com/g/ArgentCrusade/flysystem-selectel/badges/quality-score.png?b=master 126 | 127 | [link-packagist]: https://packagist.org/packages/argentcrusade/flysystem-selectel 128 | [link-travis]: https://travis-ci.org/ArgentCrusade/flysystem-selectel 129 | [link-styleci]: https://styleci.io/repos/84637792 130 | [link-scrutinizer]: https://scrutinizer-ci.com/g/ArgentCrusade/flysystem-selectel/ 131 | [link-author]: https://github.com/tzurbaev 132 | -------------------------------------------------------------------------------- /src/SelectelAdapter.php: -------------------------------------------------------------------------------- 1 | container = $container; 32 | } 33 | 34 | /** 35 | * Loads file from container. 36 | * 37 | * @param string $path Path to file. 38 | * 39 | * @return \ArgentCrusade\Selectel\CloudStorage\Contracts\FileContract 40 | */ 41 | protected function getFile($path) 42 | { 43 | return $this->container->files()->find($path); 44 | } 45 | 46 | /** 47 | * Transforms internal files array to Flysystem-compatible one. 48 | * 49 | * @param array $files Original Selectel's files array. 50 | * 51 | * @return array 52 | */ 53 | protected function transformFiles($files) 54 | { 55 | $result = []; 56 | 57 | foreach ($files as $file) { 58 | $result[] = [ 59 | 'type' => $file['content_type'] === 'application/directory' ? 'dir' : 'file', 60 | 'path' => $file['name'], 61 | 'size' => intval($file['bytes']), 62 | 'timestamp' => strtotime($file['last_modified']), 63 | 'mimetype' => $file['content_type'], 64 | ]; 65 | } 66 | 67 | return $result; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public function has($path) 74 | { 75 | return $this->container->files()->exists($path); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function read($path) 82 | { 83 | try { 84 | $file = $this->getFile($path); 85 | } catch (FileNotFoundException $e) { 86 | return false; 87 | } 88 | 89 | $contents = $file->read(); 90 | 91 | return compact('contents'); 92 | } 93 | 94 | /** 95 | * {@inheritdoc} 96 | */ 97 | public function readStream($path) 98 | { 99 | try { 100 | $file = $this->getFile($path); 101 | } catch (FileNotFoundException $e) { 102 | return false; 103 | } 104 | 105 | $stream = $file->readStream(); 106 | 107 | rewind($stream); 108 | 109 | return compact('stream'); 110 | } 111 | 112 | /** 113 | * {@inheritdoc} 114 | */ 115 | public function listContents($directory = '', $recursive = false) 116 | { 117 | $files = $this->container->files()->withPrefix($directory)->get(); 118 | $result = $this->transformFiles($files); 119 | 120 | return $result; 121 | } 122 | 123 | /** 124 | * {@inheritdoc} 125 | */ 126 | public function getMetadata($path) 127 | { 128 | $files = $this->listContents($path); 129 | 130 | return isset($files[0]) ? $files[0] : false; 131 | } 132 | 133 | /** 134 | * {@inheritdoc} 135 | */ 136 | public function getSize($path) 137 | { 138 | return $this->getMetadata($path); 139 | } 140 | 141 | /** 142 | * {@inheritdoc} 143 | */ 144 | public function getMimetype($path) 145 | { 146 | return $this->getMetadata($path); 147 | } 148 | 149 | /** 150 | * {@inheritdoc} 151 | */ 152 | public function getTimestamp($path) 153 | { 154 | return $this->getMetadata($path); 155 | } 156 | 157 | /** 158 | * {@inheritdoc} 159 | */ 160 | public function write($path, $contents, Config $config) 161 | { 162 | return $this->writeToContainer('String', $path, $contents); 163 | } 164 | 165 | /** 166 | * {@inheritdoc} 167 | */ 168 | public function writeStream($path, $resource, Config $config) 169 | { 170 | return $this->writeToContainer('Stream', $path, $resource); 171 | } 172 | 173 | /** 174 | * Writes string or stream to container. 175 | * 176 | * @param string $type Upload type 177 | * @param string $path File path 178 | * @param string|resource $payload String content or Stream resource 179 | * 180 | * @return array|bool 181 | */ 182 | protected function writeToContainer($type, $path, $payload) 183 | { 184 | try { 185 | $this->container->{'uploadFrom'.$type}($path, $payload); 186 | } catch (UploadFailedException $e) { 187 | return false; 188 | } 189 | 190 | return $this->getMetadata($path); 191 | } 192 | 193 | /** 194 | * {@inheritdoc} 195 | */ 196 | public function update($path, $contents, Config $config) 197 | { 198 | return $this->write($path, $contents, $config); 199 | } 200 | 201 | /** 202 | * {@inheritdoc} 203 | */ 204 | public function updateStream($path, $resource, Config $config) 205 | { 206 | return $this->writeStream($path, $resource, $config); 207 | } 208 | 209 | /** 210 | * {@inheritdoc} 211 | */ 212 | public function rename($path, $newpath) 213 | { 214 | try { 215 | $this->getFile($path)->rename($newpath); 216 | } catch (ApiRequestFailedException $e) { 217 | return false; 218 | } 219 | 220 | return true; 221 | } 222 | 223 | /** 224 | * {@inheritdoc} 225 | */ 226 | public function copy($path, $newpath) 227 | { 228 | try { 229 | $this->getFile($path)->copy($newpath); 230 | } catch (ApiRequestFailedException $e) { 231 | return false; 232 | } 233 | 234 | return true; 235 | } 236 | 237 | /** 238 | * {@inheritdoc} 239 | */ 240 | public function delete($path) 241 | { 242 | try { 243 | $this->getFile($path)->delete(); 244 | } catch (ApiRequestFailedException $e) { 245 | return false; 246 | } 247 | 248 | return true; 249 | } 250 | 251 | /** 252 | * {@inheritdoc} 253 | */ 254 | public function deleteDir($path) 255 | { 256 | try { 257 | $this->container->deleteDir($path); 258 | } catch (ApiRequestFailedException $e) { 259 | return false; 260 | } 261 | 262 | return true; 263 | } 264 | 265 | /** 266 | * {@inheritdoc} 267 | */ 268 | public function createDir($dirname, Config $config) 269 | { 270 | try { 271 | $this->container->createDir($dirname); 272 | } catch (ApiRequestFailedException $e) { 273 | return false; 274 | } 275 | 276 | return $this->getMetadata($dirname); 277 | } 278 | 279 | /** 280 | * Get full URL to given path. 281 | * 282 | * @param string $path = '' 283 | * 284 | * @return string 285 | */ 286 | public function getUrl($path = '') 287 | { 288 | return $this->container->url($path); 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /tests/SelectelAdapterTest.php: -------------------------------------------------------------------------------- 1 | 'path/to/file', 19 | 'content_type' => 'text/plain', 20 | 'bytes' => 1024, 21 | 'last_modified' => '2000-01-01 00:00:00', 22 | ], 23 | ]); 24 | 25 | $files = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\FluentFilesLoader'); 26 | $files->shouldReceive('withPrefix')->andReturn($files); 27 | $files->shouldReceive('get')->andReturn($collection); 28 | 29 | $mock = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\Container'); 30 | $mock->shouldReceive('type')->andReturn('public'); 31 | $mock->shouldReceive('files')->andReturn($files); 32 | 33 | return [ 34 | [new SelectelAdapter($mock), $mock, $files, $collection], 35 | ]; 36 | } 37 | 38 | public function metaDataProvider() 39 | { 40 | $collection = new Collection([ 41 | [ 42 | 'name' => 'path/to/file', 43 | 'content_type' => 'text/plain', 44 | 'bytes' => 1024, 45 | 'last_modified' => '2000-01-01 00:00:00', 46 | ], 47 | ]); 48 | 49 | $files = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\FluentFilesLoader'); 50 | $files->shouldReceive('withPrefix')->andReturn($files); 51 | $files->shouldReceive('get')->andReturn($collection); 52 | 53 | $mock = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\Container'); 54 | $mock->shouldReceive('type')->andReturn('public'); 55 | $mock->shouldReceive('files')->andReturn($files); 56 | 57 | $adapter = new SelectelAdapter($mock); 58 | 59 | return [ 60 | [ 61 | 'method' => 'getMetadata', 62 | 'adapter' => $adapter, 63 | ], 64 | [ 65 | 'method' => 'getMimetype', 66 | 'adapter' => $adapter, 67 | ], 68 | [ 69 | 'method' => 'getTimestamp', 70 | 'adapter' => $adapter, 71 | ], 72 | [ 73 | 'method' => 'getSize', 74 | 'adapter' => $adapter, 75 | ], 76 | ]; 77 | } 78 | 79 | /** 80 | * @dataProvider metaDataProvider 81 | */ 82 | public function testMetaData($method, $adapter) 83 | { 84 | $result = $adapter->{$method}('path'); 85 | 86 | $this->assertInternalType('array', $result); 87 | } 88 | 89 | /** 90 | * @dataProvider selectelProvider 91 | */ 92 | public function testHas($adapter, $mock, $files) 93 | { 94 | $files->shouldReceive('exists')->andReturn(true); 95 | 96 | $this->assertTrue($adapter->has('something')); 97 | } 98 | 99 | /** 100 | * @dataProvider selectelProvider 101 | */ 102 | public function testUrl($adapter, $mock, $files) 103 | { 104 | $mock->shouldReceive('url')->with('/file.txt')->andReturn('https://static.example.org/file.txt'); 105 | $mock->shouldReceive('url')->with('file.txt')->andReturn('https://static.example.org/file.txt'); 106 | 107 | $this->assertEquals('https://static.example.org/file.txt', $adapter->getUrl('/file.txt')); 108 | $this->assertEquals('https://static.example.org/file.txt', $adapter->getUrl('file.txt')); 109 | } 110 | 111 | /** 112 | * @dataProvider selectelProvider 113 | */ 114 | public function testWrite($adapter, $mock) 115 | { 116 | $mock->shouldReceive('uploadFromString')->andReturn(md5('test')); 117 | 118 | $result = $adapter->write('something', 'contents', new Config()); 119 | $this->assertInternalType('array', $result); 120 | $this->assertArrayHasKey('type', $result); 121 | $this->assertEquals('file', $result['type']); 122 | } 123 | 124 | /** 125 | * @dataProvider selectelProvider 126 | */ 127 | public function testUpdate($adapter, $mock) 128 | { 129 | $mock->shouldReceive('uploadFromString')->andReturn(md5('test')); 130 | 131 | $result = $adapter->update('something', 'contents', new Config()); 132 | $this->assertInternalType('array', $result); 133 | $this->assertArrayHasKey('type', $result); 134 | $this->assertEquals('file', $result['type']); 135 | } 136 | 137 | /** 138 | * @dataProvider selectelProvider 139 | */ 140 | public function testWriteStream($adapter, $mock) 141 | { 142 | $mock->shouldReceive('uploadFromStream')->andReturn(md5('test')); 143 | 144 | $file = tmpfile(); 145 | $result = $adapter->writeStream('something', $file, new Config()); 146 | $this->assertInternalType('array', $result); 147 | $this->assertArrayHasKey('type', $result); 148 | $this->assertEquals('file', $result['type']); 149 | fclose($file); 150 | } 151 | 152 | /** 153 | * @dataProvider selectelProvider 154 | */ 155 | public function testUpdateStream($adapter, $mock) 156 | { 157 | $mock->shouldReceive('uploadFromStream')->andReturn(md5('test')); 158 | 159 | $file = tmpfile(); 160 | $result = $adapter->updateStream('something', $file, new Config()); 161 | $this->assertInternalType('array', $result); 162 | $this->assertArrayHasKey('type', $result); 163 | $this->assertEquals('file', $result['type']); 164 | fclose($file); 165 | } 166 | 167 | /** 168 | * @dataProvider selectelProvider 169 | */ 170 | public function testRead($adapter, $mock, $files) 171 | { 172 | $file = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\File'); 173 | $file->shouldReceive('read')->andReturn('something'); 174 | $files->shouldReceive('find')->andReturn($file); 175 | 176 | $result = $adapter->read('something'); 177 | $this->assertInternalType('array', $result); 178 | $this->assertArrayHasKey('contents', $result); 179 | } 180 | 181 | /** 182 | * @dataProvider selectelProvider 183 | */ 184 | public function testReadStream($adapter, $mock, $files) 185 | { 186 | $stream = tmpfile(); 187 | fwrite($stream, 'something'); 188 | 189 | $file = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\File'); 190 | $file->shouldReceive('readStream')->andReturn($stream); 191 | $files->shouldReceive('find')->andReturn($file); 192 | 193 | $result = $adapter->readStream('something'); 194 | $this->assertInternalType('array', $result); 195 | $this->assertArrayHasKey('stream', $result); 196 | $this->assertEquals('something', fread($result['stream'], 1024)); 197 | 198 | fclose($stream); 199 | } 200 | 201 | /** 202 | * @dataProvider selectelProvider 203 | */ 204 | public function testRename($adapter, $mock, $files) 205 | { 206 | $file = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\File'); 207 | $file->shouldReceive('rename')->andReturn('newpath'); 208 | $files->shouldReceive('find')->andReturn($file); 209 | 210 | $this->assertTrue($adapter->rename('oldpath', 'newpath')); 211 | } 212 | 213 | /** 214 | * @dataProvider selectelProvider 215 | */ 216 | public function testCopy($adapter, $mock, $files) 217 | { 218 | $file = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\File'); 219 | $file->shouldReceive('copy')->andReturn('newpath'); 220 | $files->shouldReceive('find')->andReturn($file); 221 | 222 | $this->assertTrue($adapter->copy('from', 'to')); 223 | } 224 | 225 | /** 226 | * @dataProvider selectelProvider 227 | */ 228 | public function testCreateDir($adapter, $mock) 229 | { 230 | $mock->shouldReceive('createDir')->andReturn(md5('test')); 231 | $result = $adapter->createDir('something', new Config()); 232 | 233 | $this->assertInternalType('array', $result); 234 | } 235 | 236 | /** 237 | * @dataProvider selectelProvider 238 | */ 239 | public function testDelete($adapter, $mock, $files) 240 | { 241 | $file = Mockery::mock('ArgentCrusade\Selectel\CloudStorage\File'); 242 | $file->shouldReceive('delete')->andReturn(true); 243 | $files->shouldReceive('find')->andReturn($file); 244 | 245 | $mock->shouldReceive('deleteDir')->andReturn(true); 246 | 247 | $this->assertTrue($adapter->delete('something')); 248 | $this->assertTrue($adapter->deleteDir('something')); 249 | } 250 | } 251 | --------------------------------------------------------------------------------