Skip to content

Commit

Permalink
Turn path prefixing into an adapter decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
frankdejonge committed Sep 9, 2022
1 parent 97a3c53 commit 6145d84
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
<?php

namespace League\Flysystem;

namespace League\Flysystem\PathPrefixing;

use Generator;
use League\Flysystem\Config;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\PathPrefixer;
use League\Flysystem\UnableToCheckDirectoryExistence;
use League\Flysystem\UnableToCheckFileExistence;
use League\Flysystem\UnableToCopyFile;
use League\Flysystem\UnableToCreateDirectory;
use League\Flysystem\UnableToDeleteDirectory;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToReadFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToSetVisibility;
use League\Flysystem\UnableToWriteFile;
use Throwable;

class PathPrefixedFilesystem implements FilesystemOperator
class PathPrefixedAdapter implements FilesystemAdapter
{
protected FilesystemOperator $filesystem;
protected FilesystemAdapter $adapter;
private PathPrefixer $prefix;

/**
* @internal
*/
public function __construct(FilesystemOperator $filesystem, string $prefix)
public function __construct(FilesystemAdapter $adapter, string $prefix)
{
if (empty($prefix)) {
throw new \InvalidArgumentException('The prefix must not be empty.');
}

$this->filesystem = $filesystem;
$this->adapter = $adapter;
$this->prefix = new PathPrefixer($prefix);
}

public function has(string $location): bool
{
return $this->filesystem->has($this->preparePath($location));
}

public function read(string $location): string
{
try {
return $this->filesystem->read($this->preparePath($location));
return $this->adapter->read($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToReadFile::fromLocation($location, $previous->getMessage(), $previous);
}
Expand All @@ -39,23 +50,23 @@ public function read(string $location): string
public function readStream(string $location)
{
try {
return $this->filesystem->readStream($this->preparePath($location));
return $this->adapter->readStream($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToReadFile::fromLocation($location, $previous->getMessage(), $previous);
}
}

public function listContents(string $location, bool $deep = self::LIST_SHALLOW): DirectoryListing
public function listContents(string $location, bool $deep): Generator
{
return $this->filesystem->listContents($this->preparePath($location), $deep)->map(
fn(StorageAttributes $attributes) => $attributes->withPath($this->stripPath($attributes->path()))
);
foreach ($this->adapter->listContents($this->prefix->prefixPath($location), $deep) as $attributes) {
yield $attributes->withPath($this->prefix->stripPrefix($attributes->path()));
}
}

public function fileExists(string $location): bool
{
try {
return $this->filesystem->fileExists($this->preparePath($location));
return $this->adapter->fileExists($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToCheckFileExistence::forLocation($location, $previous);
}
Expand All @@ -64,61 +75,61 @@ public function fileExists(string $location): bool
public function directoryExists(string $location): bool
{
try {
return $this->filesystem->directoryExists($this->preparePath($location));
return $this->adapter->directoryExists($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToCheckDirectoryExistence::forLocation($location, $previous);
}
}

public function lastModified(string $path): int
public function lastModified(string $path): FileAttributes
{
try {
return $this->filesystem->lastModified($this->preparePath($path));
return $this->adapter->lastModified($this->prefix->prefixPath($path));
} catch (Throwable $previous) {
throw UnableToRetrieveMetadata::lastModified($path, $previous->getMessage(), $previous);
}
}

public function fileSize(string $path): int
public function fileSize(string $path): FileAttributes
{
try {
return $this->filesystem->fileSize($this->preparePath($path));
return $this->adapter->fileSize($this->prefix->prefixPath($path));
} catch (Throwable $previous) {
throw UnableToRetrieveMetadata::fileSize($path, $previous->getMessage(), $previous);
}
}

public function mimeType(string $path): string
public function mimeType(string $path): FileAttributes
{
try {
return $this->filesystem->mimeType($this->preparePath($path));
return $this->adapter->mimeType($this->prefix->prefixPath($path));
} catch (Throwable $previous) {
throw UnableToRetrieveMetadata::mimeType($path, $previous->getMessage(), $previous);
}
}

public function visibility(string $path): string
public function visibility(string $path): FileAttributes
{
try {
return $this->filesystem->visibility($this->preparePath($path));
return $this->adapter->visibility($this->prefix->prefixPath($path));
} catch (Throwable $previous) {
throw UnableToRetrieveMetadata::visibility($path, $previous->getMessage(), $previous);
}
}

public function write(string $location, string $contents, array $config = []): void
public function write(string $location, string $contents, Config $config): void
{
try {
$this->filesystem->write($this->preparePath($location), $contents, $config);
$this->adapter->write($this->prefix->prefixPath($location), $contents, $config);
} catch (Throwable $previous) {
throw UnableToWriteFile::atLocation($location, $previous->getMessage(), $previous);
}
}

public function writeStream(string $location, $contents, array $config = []): void
public function writeStream(string $location, $contents, Config $config): void
{
try {
$this->filesystem->writeStream($this->preparePath($location), $contents, $config);
$this->adapter->writeStream($this->prefix->prefixPath($location), $contents, $config);
} catch (Throwable $previous) {
throw UnableToWriteFile::atLocation($location, $previous->getMessage(), $previous);
}
Expand All @@ -127,7 +138,7 @@ public function writeStream(string $location, $contents, array $config = []): vo
public function setVisibility(string $path, string $visibility): void
{
try {
$this->filesystem->setVisibility($this->preparePath($path), $visibility);
$this->adapter->setVisibility($this->prefix->prefixPath($path), $visibility);
} catch (Throwable $previous) {
throw UnableToSetVisibility::atLocation($path, $previous->getMessage(), $previous);
}
Expand All @@ -136,7 +147,7 @@ public function setVisibility(string $path, string $visibility): void
public function delete(string $location): void
{
try {
$this->filesystem->delete($this->preparePath($location));
$this->adapter->delete($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToDeleteFile::atLocation($location, $previous->getMessage(), $previous);
}
Expand All @@ -145,46 +156,36 @@ public function delete(string $location): void
public function deleteDirectory(string $location): void
{
try {
$this->filesystem->deleteDirectory($this->preparePath($location));
$this->adapter->deleteDirectory($this->prefix->prefixPath($location));
} catch (Throwable $previous) {
throw UnableToDeleteDirectory::atLocation($location, $previous->getMessage(), $previous);
}
}

public function createDirectory(string $location, array $config = []): void
public function createDirectory(string $location, Config $config): void
{
try {
$this->filesystem->createDirectory($this->preparePath($location), $config);
$this->adapter->createDirectory($this->prefix->prefixPath($location), $config);
} catch (Throwable $previous) {
throw UnableToCreateDirectory::atLocation($location, $previous->getMessage(), $previous);
}
}

public function move(string $source, string $destination, array $config = []): void
public function move(string $source, string $destination, Config $config): void
{
try {
$this->filesystem->move($this->preparePath($source), $this->preparePath($destination), $config);
$this->adapter->move($this->prefix->prefixPath($source), $this->prefix->prefixPath($destination), $config);
} catch (Throwable $previous) {
throw UnableToMoveFile::fromLocationTo($source, $destination, $previous);
}
}

public function copy(string $source, string $destination, array $config = []): void
public function copy(string $source, string $destination, Config $config): void
{
try {
$this->filesystem->copy($this->preparePath($source), $this->preparePath($destination), $config);
$this->adapter->copy($this->prefix->prefixPath($source), $this->prefix->prefixPath($destination), $config);
} catch (Throwable $previous) {
throw UnableToCopyFile::fromLocationTo($source, $destination, $previous);
}
}

private function stripPath(string $path): string
{
return $this->prefix->stripPrefix($path);
}

private function preparePath(string $path): string
{
return $this->prefix->prefixPath($path);
}
}
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
<?php

namespace League\Flysystem;
namespace League\Flysystem\PathPrefixing;

use League\Flysystem\Config;
use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
use League\Flysystem\Visibility;
use PHPUnit\Framework\TestCase;

class PathPrefixedFilesystemTest extends TestCase
use function iterator_to_array;

class PathPrefixedAdapterTest extends TestCase
{
public function testPrefix(): void
{
$fs = new Filesystem(new InMemoryFilesystemAdapter());
$prefix = new PathPrefixedFilesystem($fs, 'foo');
$adapter = new InMemoryFilesystemAdapter();
$prefix = new PathPrefixedAdapter($adapter, 'foo');

$prefix->write('foo.txt', 'bla');
$prefix->write('foo.txt', 'bla', new Config);
static::assertTrue($prefix->fileExists('foo.txt'));
static::assertTrue($prefix->has('foo.txt'));
static::assertFalse($prefix->directoryExists('foo.txt'));
static::assertTrue($fs->has('foo/foo.txt'));
static::assertFalse($fs->directoryExists('foo/foo.txt'));
static::assertTrue($adapter->fileExists('foo/foo.txt'));
static::assertFalse($adapter->directoryExists('foo/foo.txt'));

static::assertSame('bla', $prefix->read('foo.txt'));
static::assertSame('bla', stream_get_contents($prefix->readStream('foo.txt')));
static::assertSame('text/plain', $prefix->mimeType('foo.txt'));
static::assertSame(3, $prefix->fileSize('foo.txt'));
static::assertSame(Visibility::PUBLIC, $prefix->visibility('foo.txt'));
static::assertSame('text/plain', $prefix->mimeType('foo.txt')->mimeType());
static::assertSame(3, $prefix->fileSize('foo.txt')->fileSize());
static::assertSame(Visibility::PUBLIC, $prefix->visibility('foo.txt')->visibility());
$prefix->setVisibility('foo.txt', Visibility::PRIVATE);
static::assertSame(Visibility::PRIVATE, $prefix->visibility('foo.txt'));
static::assertEqualsWithDelta($prefix->lastModified('foo.txt'), time(), 2);
static::assertSame(Visibility::PRIVATE, $prefix->visibility('foo.txt')->visibility());
static::assertEqualsWithDelta($prefix->lastModified('foo.txt')->lastModified(), time(), 2);

$prefix->copy('foo.txt', 'bla.txt');
static::assertTrue($prefix->has('bla.txt'));
$prefix->copy('foo.txt', 'bla.txt', new Config);
static::assertTrue($prefix->fileExists('bla.txt'));

$prefix->createDirectory('dir');
$prefix->createDirectory('dir', new Config());
static::assertTrue($prefix->directoryExists('dir'));
static::assertFalse($prefix->directoryExists('dir2'));
$prefix->deleteDirectory('dir');
static::assertFalse($prefix->directoryExists('dir'));

$prefix->move('bla.txt', 'bla2.txt');
static::assertFalse($prefix->has('bla.txt'));
static::assertTrue($prefix->has('bla2.txt'));
$prefix->move('bla.txt', 'bla2.txt', new Config());
static::assertFalse($prefix->fileExists('bla.txt'));
static::assertTrue($prefix->fileExists('bla2.txt'));

$prefix->delete('bla2.txt');
static::assertFalse($prefix->has('bla2.txt'));
static::assertFalse($prefix->fileExists('bla2.txt'));

$prefix->createDirectory('test');
$prefix->createDirectory('test', new Config());

$files = $prefix->listContents('', true)->toArray();
$files = iterator_to_array($prefix->listContents('', true));
static::assertCount(2, $files);
}

public function testWriteStream(): void
{
$fs = new Filesystem(new InMemoryFilesystemAdapter());
$prefix = new PathPrefixedFilesystem($fs, 'foo');
$adapter = new InMemoryFilesystemAdapter();
$prefix = new PathPrefixedAdapter($adapter, 'foo');
$tmpFile = sys_get_temp_dir() . '/' . uniqid('test', true);
file_put_contents($tmpFile, 'test');

$prefix->writeStream('a.txt', fopen($tmpFile, 'rb'));
$prefix->writeStream('a.txt', fopen($tmpFile, 'rb'), new Config());

static::assertTrue($prefix->fileExists('a.txt'));
static::assertSame('test', $prefix->read('a.txt'));
Expand All @@ -69,6 +72,6 @@ public function testWriteStream(): void
public function testEmptyPrefix(): void
{
static::expectException(\InvalidArgumentException::class);
new PathPrefixedFilesystem(new Filesystem(new InMemoryFilesystemAdapter()), '');
new PathPrefixedAdapter(new InMemoryFilesystemAdapter(), '');
}
}

0 comments on commit 6145d84

Please sign in to comment.