Browse Source

feature: Create cache path if it does not exist (#7109)

Greg Korba 1 year ago
parent
commit
e2ce97520c
2 changed files with 34 additions and 3 deletions
  1. 7 1
      src/Cache/FileHandler.php
  2. 27 2
      tests/Cache/FileHandlerTest.php

+ 7 - 1
src/Cache/FileHandler.php

@@ -77,9 +77,15 @@ final class FileHandler implements FileHandlerInterface
         } else {
             $dir = \dirname($this->file);
 
+            // Ensure path is created, but ignore if already exists. FYI: ignore EA suggestion in IDE,
+            // `mkdir()` returns `false` for existing paths, so we can't mix it with `is_dir()` in one condition.
+            if (!is_dir($dir)) {
+                @mkdir($dir, 0777, true);
+            }
+
             if (!is_dir($dir)) {
                 throw new IOException(
-                    sprintf('Directory of cache file "%s" does not exists.', $this->file),
+                    sprintf('Directory of cache file "%s" does not exists and couldn\'t be created.', $this->file),
                     0,
                     null,
                     $this->file

+ 27 - 2
tests/Cache/FileHandlerTest.php

@@ -99,11 +99,11 @@ final class FileHandlerTest extends TestCase
 
     public function testWriteThrowsIOExceptionIfFileCanNotBeWritten(): void
     {
-        $file = __DIR__.'/non-existent-directory/.php-cs-fixer.cache';
+        $file = '/../"/out/of/range/cache.json'; // impossible path
 
         $this->expectException(IOException::class);
         $this->expectExceptionMessageMatches(sprintf(
-            '#^Directory of cache file "%s" does not exists.#',
+            '#^Directory of cache file "%s" does not exists and couldn\'t be created\.#',
             preg_quote($file, '#')
         ));
 
@@ -182,6 +182,31 @@ final class FileHandlerTest extends TestCase
         @unlink($file);
     }
 
+    public function testCachePathIsCreated(): void
+    {
+        $dir = __DIR__.'/../Fixtures/cache-file-handler/one/two/three';
+        $file = $dir.'/cache.json';
+        $cleanPath = static function () use ($dir, $file): void {
+            @unlink($file);
+            for ($i = 0; $i <= 2; ++$i) {
+                @rmdir(0 === $i ? $dir : \dirname($dir, $i));
+            }
+        };
+
+        $cleanPath();
+
+        self::assertDirectoryDoesNotExist($dir);
+        self::assertFileDoesNotExist($file);
+
+        $handler = new FileHandler($file);
+        $handler->write(new Cache($this->createSignature()));
+
+        self::assertDirectoryExists($dir);
+        self::assertFileExists($file);
+
+        $cleanPath();
+    }
+
     private function getFile(): string
     {
         return __DIR__.'/.php-cs-fixer.cache';