From 3b99dd581be54b6d10496a7fcc3f1fbe4102cb8f Mon Sep 17 00:00:00 2001 From: Oleksii Prudkyi Date: Tue, 10 Dec 2024 21:14:45 +0100 Subject: [PATCH] feat: correctly handle errors in ftpRawlist - throw exception compatible with flysystem listContents api - add tests with subfolders - fixes https://github.com/oprudkyi/flysystem-curlftp/issues/6 --- src/CurlFtpAdapter.php | 9 ++++++++ tests/CurlFtpAdapterTest.php | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/CurlFtpAdapter.php b/src/CurlFtpAdapter.php index 164d678..346d60e 100644 --- a/src/CurlFtpAdapter.php +++ b/src/CurlFtpAdapter.php @@ -16,6 +16,7 @@ use League\Flysystem\UnableToCreateDirectory; use League\Flysystem\UnableToDeleteDirectory; use League\Flysystem\UnableToDeleteFile; +use League\Flysystem\UnableToListContents; use League\Flysystem\UnableToMoveFile; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; @@ -508,6 +509,14 @@ private function ftpRawlist(string $options, string $path): array $request = rtrim('LIST '.$options.$path); $listing = $this->connection()->exec([CURLOPT_CUSTOMREQUEST => $request]); + if ($listing === false) { + throw UnableToListContents::atLocation( + $path, + strpos($options, 'R') !== false, + new RuntimeException($this->connection->lastError()), + ); + } + return explode(PHP_EOL, $listing); } diff --git a/tests/CurlFtpAdapterTest.php b/tests/CurlFtpAdapterTest.php index 9aeb809..4684729 100644 --- a/tests/CurlFtpAdapterTest.php +++ b/tests/CurlFtpAdapterTest.php @@ -229,6 +229,30 @@ public function testListContentsEmptyPath(string $path): void $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname($path), false), false)); } + /** + * @dataProvider withSubSubFolderProvider + */ + public function testListContentsDeep(string $path): void + { + $contents = $this->faker()->text; + $this->createResourceFile($path, $contents); + + $this->assertCount(1, iterator_to_array($this->adapter->listContents(dirname($path), true), false)); + $this->assertCount(2, iterator_to_array($this->adapter->listContents(dirname(dirname($path)), true), false)); + $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname(dirname($path)) . '/not exists folder', true), false)); + } + + /** + * @dataProvider withSubSubFolderProvider + */ + public function testListContentsDeepEmptyPath(string $path): void + { + $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname($path), true), false)); + $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname(dirname($path)), true), false)); + $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname(dirname($path)) . '/not exists folder', true), false)); + $this->assertCount(0, iterator_to_array($this->adapter->listContents(dirname(dirname($path)) . '/not exists folder', false), false)); + } + /** * Tests that a FTP server is still in root directory as its working directory * after reading a file, especially if this file is in a subfolder. @@ -364,4 +388,20 @@ public static function withSubFolderProvider(): array [self::faker()->word.'/'.self::randomFileName()], ]; } + + public static function withSubSubFolderProvider(): array + { + return [ + ['test/test/test.txt'], + ['тёст/тёст/тёст.txt'], + ['test 1/test 1/test.txt'], + ['test/test/test 1.txt'], + ['test 1/test 2/test 3.txt'], + [self::faker()->word.'/'.self::faker()->word.'/'.self::randomFileName()], + [self::faker()->word.'/'.self::faker()->word.'/'.self::randomFileName()], + [self::faker()->word.'/'.self::faker()->word.'/'.self::randomFileName()], + [self::faker()->word.'/'.self::faker()->word.'/'.self::randomFileName()], + [self::faker()->word.'/'.self::faker()->word.'/'.self::randomFileName()], + ]; + } }