Skip to content

Commit

Permalink
[Flystem] Add FlysystemV2 adapter for version 2 support of flysystem.
Browse files Browse the repository at this point in the history
Done as a new adapter to allows users to use the existing adapter for
flysystem version 1.
  • Loading branch information
Ian Jenkins committed Jun 30, 2021
1 parent 80694cf commit 14b3d0c
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
- { php: '7.4', packages: 'google/apiclient:^1.1.3', phpspec: 'spec/Gaufrette/Adapter/GoogleCloudStorageSpec.php' }
- { php: '7.4', packages: 'doctrine/dbal:^2.3', phpspec: 'spec/Gaufrette/Adapter/DoctrineDbalSpec.php' }
- { php: '7.4', packages: 'league/flysystem:^1.0', phpspec: 'spec/Gaufrette/Adapter/FlysystemSpec.php' }
- { php: '7.4', packages: 'league/flysystem:^2.0', phpspec: 'spec/Gaufrette/Adapter/FlysystemV2Spec.php' }
- { php: '7.4', packages: 'microsoft/azure-storage-blob:^1.0', phpspec: 'spec/Gaufrette/Adapter/AzureBlobStore' }
- { php: '7.4', packages: 'mongodb/mongodb:^1.1', phpspec: 'spec/Gaufrette/Adapter/GridFSSpec.php' }
- { php: '7.4', packages: 'phpseclib/phpseclib:^2.0', phpspec: 'spec/Gaufrette/Adapter/PhpseclibSftpSpec.php' }
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ remove-phpspec:
rm spec/Gaufrette/Adapter/GoogleCloudStorageSpec.php
rm spec/Gaufrette/Adapter/DoctrineDbalSpec.php
rm spec/Gaufrette/Adapter/FlysystemSpec.php
rm spec/Gaufrette/Adapter/FlysystemV2Spec.php
rm -r spec/Gaufrette/Adapter/AzureBlobStorage
rm spec/Gaufrette/Adapter/GridFSSpec.php
rm spec/Gaufrette/Adapter/PhpseclibSftpSpec.php
Expand Down
98 changes: 98 additions & 0 deletions spec/Gaufrette/Adapter/FlysystemV2Spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace spec\Gaufrette\Adapter;

use League\Flysystem\DirectoryAttributes;
use League\Flysystem\FileAttributes;
use PhpSpec\ObjectBehavior;

class FlysystemV2Spec extends ObjectBehavior
{
function let(\League\Flysystem\FilesystemAdapter $adapter, \League\Flysystem\Config $config)
{
$this->beConstructedWith($adapter, $config);
}

function it_is_adapter()
{
$this->shouldImplement('Gaufrette\Adapter');
}

function it_is_list_keys_aware()
{
$this->shouldImplement('Gaufrette\Adapter\ListKeysAware');
}

function it_reads_file(\League\Flysystem\FilesystemAdapter $adapter)
{
$adapter->read('filename')->willReturn('Hello.');
$this->read('filename')->shouldReturn('Hello.');
}

function it_writes_file(\League\Flysystem\FilesystemAdapter $adapter, \League\Flysystem\Config $config)
{
$this->shouldNotThrow('League\Flysystem\UnableToWriteFile')->duringWrite('filename', 'Hello.', $config);
$adapter->fileSize('filename')->willReturn(new FileAttributes('filename', 100));
$adapter->write('filename', 'Hello.', $config)->shouldBeCalled();

$this->write('filename', 'Hello.')->shouldReturn(100);
}

function it_checks_if_file_exists(\League\Flysystem\FilesystemAdapter $adapter)
{
$adapter->fileExists('filename')->willReturn(true);

$this->exists('filename')->shouldReturn(true);
}

function it_fetches_keys(\League\Flysystem\FilesystemAdapter $adapter)
{
$adapter->listContents('', true)->willReturn(
yield new DirectoryAttributes('folder', null, 1457104978)
);

$this->keys()->shouldReturn(['folder']);
}

function it_lists_keys(\League\Flysystem\FilesystemAdapter $adapter)
{
$adapter->listContents('', true)->willReturn([
new DirectoryAttributes('folder', null, 1457104978),
new FileAttributes('file', 22, null, 1457104978),
]
);

$this->listKeys()->shouldReturn([
'keys' => ['file'],
'dirs' => ['folder'],
]);
}

function it_fetches_mtime(\League\Flysystem\FilesystemAdapter $adapter)
{
$adapter->lastModified('filename')->willReturn(new FileAttributes('filename', null, null, 1457104978));

$this->mtime('filename')->shouldReturn(1457104978);
}

function it_deletes_file(\League\Flysystem\FilesystemAdapter $adapter)
{
$this->shouldNotThrow('League\Flysystem\UnableToDeleteFile')->duringDelete('filename');
$adapter->delete('filename')->shouldBeCalled();

$this->delete('filename')->shouldReturn(true);
}

function it_renames_file(\League\Flysystem\FilesystemAdapter $adapter, \League\Flysystem\Config $config)
{
$this->shouldNotThrow('League\Flysystem\UnableToMoveFile')->duringRename('oldfilename', 'newfilename');
$adapter->move('oldfilename', 'newfilename', $config)->shouldBeCalled();

$this->rename('oldfilename', 'newfilename')->shouldReturn(true);
}

function it_does_not_support_is_directory(\League\Flysystem\FilesystemAdapter $adapter)
{
$this->shouldThrow('Gaufrette\Exception\UnsupportedAdapterMethodException')->duringisDirectory('folder');
}
}
171 changes: 171 additions & 0 deletions src/Gaufrette/Adapter/FlysystemV2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?php

namespace Gaufrette\Adapter;

use Gaufrette\Adapter;
use Gaufrette\Exception\UnsupportedAdapterMethodException;
use League\Flysystem\Config;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToWriteFile;

class FlysystemV2 implements Adapter, ListKeysAware
{
/**
* @var FilesystemAdapter
*/
private $adapter;

/**
* @var Config
*/
private $config;

/**
* @param FilesystemAdapter $adapter
* @param Config|array|null $config
*/
public function __construct(FilesystemAdapter $adapter, $config = null)
{
if (!interface_exists(FilesystemAdapter::class)) {
throw new \LogicException('You need to install package "league/flysystem" to use this adapter');
}

$this->adapter = $adapter;
$this->config = $this->ensureConfig($config);
}

/**
* {@inheritdoc}
*/
public function read($key)
{
return $this->adapter->read($key);
}

/**
* {@inheritdoc}
*/
public function write($key, $content)
{
try {
$this->adapter->write($key, $content, $this->config);
return $this->adapter->fileSize($key)->fileSize();
} catch(UnableToWriteFile $exception) {
return false;
}
}

/**
* {@inheritdoc}
*/
public function exists($key)
{
return $this->adapter->fileExists($key);
}

/**
* {@inheritdoc}
*/
public function keys()
{
return array_map(function (StorageAttributes $content) {
return $content->path();
}, $this->adapter->listContents('', true));
}

/**
* {@inheritdoc}
*/
public function listKeys($prefix = '')
{
$dirs = [];
$keys = [];

foreach ($this->adapter->listContents('', true) as $content) {
if (empty($prefix) || 0 === strpos($content->path(), $prefix)) {
if ($content->isDir()) {
$dirs[] = $content->path();
} else {
$keys[] = $content->path();
}
}
}

return [
'keys' => $keys,
'dirs' => $dirs,
];
}

/**
* {@inheritdoc}
*/
public function mtime($key)
{
return $this->adapter->lastModified($key)->lastModified();
}

/**
* {@inheritdoc}
*/
public function delete($key)
{
try {
$this->adapter->delete($key);
} catch (UnableToDeleteFile $exception) {
return false;
}

return true;
}

/**
* {@inheritdoc}
*/
public function rename($sourceKey, $targetKey)
{
try {
$this->adapter->move($sourceKey, $targetKey, $this->config);
} catch (UnableToMoveFile $exception) {
return false;
}

return true;
}

/**
* {@inheritdoc}
*/
public function isDirectory($key)
{
throw new UnsupportedAdapterMethodException('isDirectory is not supported by this adapter.');
}

/**
* Ensure a Config instance.
*
* @param null|array|Config $config
*
* @return Config config instance
*
* @throw LogicException
*/
private function ensureConfig($config) {
if ($config === null) {
return new Config();
}

if ($config instanceof Config) {
return $config;
}

if (is_array($config)) {
return new Config($config);
}

throw new \LogicException('A config should either be an array or a League\Flysystem\Config object.');
}
}

0 comments on commit 14b3d0c

Please sign in to comment.