Skip to content

Commit

Permalink
Added ability to set resolution strategy for copy and move conflicts.
Browse files Browse the repository at this point in the history
  • Loading branch information
frankdejonge committed Oct 19, 2023
1 parent 01e7c17 commit 8e5ac91
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

class Config
{
public const OPTION_COPY_DESTINATION_SAME_AS_SOURCE = 'copy_destination_same_as_source';
public const OPTION_MOVE_DESTINATION_SAME_AS_SOURCE = 'move_destination_same_as_source';
public const OPTION_VISIBILITY = 'visibility';
public const OPTION_DIRECTORY_VISIBILITY = 'directory_visibility';

Expand Down
23 changes: 20 additions & 3 deletions src/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,17 @@ public function move(string $source, string $destination, array $config = []): v
$to = $this->pathNormalizer->normalizePath($destination);

if ($from === $to) {
throw UnableToMoveFile::sourceAndDestinationAreTheSame($source, $destination);
}
$resolutionStrategy = $this->config->get(
Config::OPTION_MOVE_DESTINATION_SAME_AS_SOURCE,
ResolveSameSourceAndDestinationConflict::TRY,
);

if ($resolutionStrategy === ResolveSameSourceAndDestinationConflict::FAIL) {
throw UnableToMoveFile::sourceAndDestinationAreTheSame($source, $destination);
} elseif ($resolutionStrategy === ResolveSameSourceAndDestinationConflict::IGNORE) {
return;
}
}
$this->adapter->move($from, $to, $this->config->extend($config));
}

Expand All @@ -135,7 +143,16 @@ public function copy(string $source, string $destination, array $config = []): v
$to = $this->pathNormalizer->normalizePath($destination);

if ($from === $to) {
throw UnableToCopyFile::sourceAndDestinationAreTheSame($source, $destination);
$resolutionStrategy = $this->config->get(
Config::OPTION_COPY_DESTINATION_SAME_AS_SOURCE,
ResolveSameSourceAndDestinationConflict::TRY,
);

if ($resolutionStrategy === ResolveSameSourceAndDestinationConflict::FAIL) {
throw UnableToCopyFile::sourceAndDestinationAreTheSame($source, $destination);
} elseif ($resolutionStrategy === ResolveSameSourceAndDestinationConflict::IGNORE) {
return;
}
}

$this->adapter->copy($from, $to, $this->config->extend($config));
Expand Down
59 changes: 55 additions & 4 deletions src/FilesystemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,19 +485,19 @@ public function publicUrl(string $path, Config $config): string
*/
public function copying_from_and_to_the_same_location_fails(): void
{
$this->expectExceptionObject(UnableToMoveFile::sourceAndDestinationAreTheSame('from.txt', 'from.txt'));
$this->expectExceptionObject(UnableToCopyFile::fromLocationTo('from.txt', 'from.txt'));

$this->filesystem->move('from.txt', 'from.txt');
$this->filesystem->copy('from.txt', 'from.txt');
}

/**
* @test
*/
public function moving_from_and_to_the_same_location_fails(): void
{
$this->expectExceptionObject(UnableToCopyFile::sourceAndDestinationAreTheSame('from.txt', 'from.txt'));
$this->expectExceptionObject(UnableToMoveFile::fromLocationTo('from.txt', 'from.txt'));

$this->filesystem->copy('from.txt', 'from.txt');
$this->filesystem->move('from.txt', 'from.txt');
}

/**
Expand Down Expand Up @@ -611,6 +611,57 @@ public function not_being_able_to_generate_temporary_urls(): void
$filesystem->temporaryUrl('some/file.txt', new DateTimeImmutable());
}

/**
* @test
*/
public function ignoring_same_paths_for_move_and_copy(): void
{
$this->expectNotToPerformAssertions();

$filesystem = new Filesystem(
new InMemoryFilesystemAdapter(),
[
Config::OPTION_COPY_DESTINATION_SAME_AS_SOURCE => ResolveSameSourceAndDestinationConflict::IGNORE,
Config::OPTION_MOVE_DESTINATION_SAME_AS_SOURCE => ResolveSameSourceAndDestinationConflict::IGNORE,
]
);

$filesystem->move('from.txt', 'from.txt');
$filesystem->copy('from.txt', 'from.txt');
}

/**
* @test
*/
public function failing_same_paths_for_move(): void
{
$filesystem = new Filesystem(
new InMemoryFilesystemAdapter(),
[
Config::OPTION_MOVE_DESTINATION_SAME_AS_SOURCE => ResolveSameSourceAndDestinationConflict::FAIL,
]
);

$this->expectExceptionObject(UnableToMoveFile::fromLocationTo('from.txt', 'from.txt'));
$filesystem->move('from.txt', 'from.txt');
}

/**
* @test
*/
public function failing_same_paths_for_copy(): void
{
$filesystem = new Filesystem(
new InMemoryFilesystemAdapter(),
[
Config::OPTION_COPY_DESTINATION_SAME_AS_SOURCE => ResolveSameSourceAndDestinationConflict::FAIL,
]
);

$this->expectExceptionObject(UnableToCopyFile::fromLocationTo('from.txt', 'from.txt'));
$filesystem->copy('from.txt', 'from.txt');
}

/**
* @test
*/
Expand Down
8 changes: 4 additions & 4 deletions src/InMemory/InMemoryFilesystemAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,15 @@ public function listContents(string $path, bool $deep): iterable

public function move(string $source, string $destination, Config $config): void
{
$source = $this->preparePath($source);
$destination = $this->preparePath($destination);
$sourcePath = $this->preparePath($source);
$destinationPath = $this->preparePath($destination);

if ( ! $this->fileExists($source) || $this->fileExists($destination)) {
throw UnableToMoveFile::fromLocationTo($source, $destination);
}

$this->files[$destination] = $this->files[$source];
unset($this->files[$source]);
$this->files[$destinationPath] = $this->files[$sourcePath];
unset($this->files[$sourcePath]);
}

public function copy(string $source, string $destination, Config $config): void
Expand Down
4 changes: 2 additions & 2 deletions src/Local/LocalFilesystemAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ public function move(string $source, string $destination, Config $config): void
);

if ( ! @rename($sourcePath, $destinationPath)) {
throw UnableToMoveFile::fromLocationTo($sourcePath, $destinationPath);
throw UnableToMoveFile::because(error_get_last()['message'] ?? 'unknown reason', $source, $destination);
}
}

Expand All @@ -263,7 +263,7 @@ public function copy(string $source, string $destination, Config $config): void
);

if ( ! @copy($sourcePath, $destinationPath)) {
throw UnableToCopyFile::fromLocationTo($sourcePath, $destinationPath);
throw UnableToCopyFile::because(error_get_last()['message'] ?? 'unknown', $source, $destination);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/ResolveSameSourceAndDestinationConflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace League\Flysystem;

class ResolveSameSourceAndDestinationConflict
{
public const IGNORE = 'ignore';
public const FAIL = 'fail';
public const TRY = 'try';
}

0 comments on commit 8e5ac91

Please sign in to comment.