From a53c0ea9c232dbb71c4cb172f043d769882117a6 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 1 Oct 2025 15:48:14 +0530 Subject: [PATCH] feat: dirExists --- src/Storage/Device.php | 8 ++++++++ src/Storage/Device/Local.php | 11 +++++++++++ src/Storage/Device/S3.php | 24 ++++++++++++++++++++++++ tests/Storage/Device/LocalTest.php | 19 +++++++++++++++++++ tests/Storage/S3Base.php | 25 +++++++++++++++++++++++++ 5 files changed, 87 insertions(+) diff --git a/src/Storage/Device.php b/src/Storage/Device.php index ac742146..b448b274 100644 --- a/src/Storage/Device.php +++ b/src/Storage/Device.php @@ -208,6 +208,14 @@ abstract public function deletePath(string $path): bool; */ abstract public function exists(string $path): bool; + /** + * Check if directory exists + * + * @param string $path + * @return bool + */ + abstract public function directoryExists(string $path): bool; + /** * Returns given file path its size. * diff --git a/src/Storage/Device/Local.php b/src/Storage/Device/Local.php index a587a7cf..ed42499b 100644 --- a/src/Storage/Device/Local.php +++ b/src/Storage/Device/Local.php @@ -390,6 +390,17 @@ public function exists(string $path): bool return \file_exists($path); } + /** + * Check if directory exists + * + * @param string $path + * @return bool + */ + public function directoryExists(string $path): bool + { + return \is_dir($path); + } + /** * Returns given file path its size. * diff --git a/src/Storage/Device/S3.php b/src/Storage/Device/S3.php index c21bb9cb..f5a7aeba 100644 --- a/src/Storage/Device/S3.php +++ b/src/Storage/Device/S3.php @@ -632,6 +632,30 @@ public function exists(string $path): bool return true; } + /** + * Check if directory exists + * + * In S3, directories are virtual. We check if any objects exist with the given prefix. + * + * @param string $path + * @return bool + */ + public function directoryExists(string $path): bool + { + try { + // Ensure path ends with / for directory prefix search + $prefix = rtrim($path, '/').'/'; + $prefix = ltrim($prefix, '/'); // S3 specific requirement that prefix should never contain a leading slash + + $objects = $this->listObjects($prefix, 1); // Only need to check if at least one object exists + + // Check if any objects exist with this prefix + return isset($objects['KeyCount']) && (int) $objects['KeyCount'] > 0; + } catch (\Throwable $th) { + return false; + } + } + /** * Returns given file path its size. * diff --git a/tests/Storage/Device/LocalTest.php b/tests/Storage/Device/LocalTest.php index c3d91b23..0107ecfb 100644 --- a/tests/Storage/Device/LocalTest.php +++ b/tests/Storage/Device/LocalTest.php @@ -84,6 +84,25 @@ public function testFileExists() $this->object->delete($this->object->getPath('text-for-test-exists.txt')); } + public function testDirectoryExists() + { + // Test existing directory + $this->assertEquals(true, $this->object->directoryExists(__DIR__.'/../../resources/disk-a')); + $this->assertEquals(true, $this->object->directoryExists(__DIR__.'/../../resources/disk-b')); + + // Test non-existing directory + $this->assertEquals(false, $this->object->directoryExists(__DIR__.'/../../resources/nonexistent')); + + // Test creating and checking directory + $testDir = $this->object->getPath('test-directory'); + $this->assertEquals(false, $this->object->directoryExists($testDir)); + $this->assertEquals(true, $this->object->createDirectory($testDir)); + $this->assertEquals(true, $this->object->directoryExists($testDir)); + + // Cleanup + rmdir($testDir); + } + public function testMove() { $this->assertEquals($this->object->write($this->object->getPath('text-for-move.txt'), 'Hello World'), true); diff --git a/tests/Storage/S3Base.php b/tests/Storage/S3Base.php index 314cfe02..88079440 100644 --- a/tests/Storage/S3Base.php +++ b/tests/Storage/S3Base.php @@ -20,6 +20,11 @@ abstract protected function getAdapterName(): string; */ abstract protected function getAdapterDescription(): string; + /** + * @return string + */ + abstract protected function getAdapterType(): string; + /** * @var S3 */ @@ -139,6 +144,26 @@ public function testFileExists() $this->assertEquals(false, $this->object->exists($this->object->getPath('testing/kitten-5.jpg'))); } + public function testDirectoryExists() + { + // Test existing directory with files + $this->assertEquals(true, $this->object->directoryExists($this->object->getPath('testing'))); + $this->assertEquals(true, $this->object->directoryExists($this->object->getPath('testing/'))); + + // Test non-existing directory + $this->assertEquals(false, $this->object->directoryExists($this->object->getPath('nonexistent'))); + $this->assertEquals(false, $this->object->directoryExists($this->object->getPath('nonexistent/'))); + + // Test nested directory structure + $this->object->write($this->object->getPath('nested/deep/file.txt'), 'test content', 'text/plain'); + $this->assertEquals(true, $this->object->directoryExists($this->object->getPath('nested'))); + $this->assertEquals(true, $this->object->directoryExists($this->object->getPath('nested/deep'))); + $this->assertEquals(false, $this->object->directoryExists($this->object->getPath('nested/nonexistent'))); + + // Cleanup + $this->object->delete($this->object->getPath('nested/deep/file.txt')); + } + public function testMove() { $this->assertEquals(true, $this->object->write($this->object->getPath('text-for-move.txt'), 'Hello World', 'text/plain'));