diff --git a/packages/cache/src/Config/CacheConfig.php b/packages/cache/src/Config/CacheConfig.php index 8ad8fec4a..7ef121057 100644 --- a/packages/cache/src/Config/CacheConfig.php +++ b/packages/cache/src/Config/CacheConfig.php @@ -5,11 +5,13 @@ namespace Marko\Cache\Config; use Marko\Config\ConfigRepositoryInterface; +use Marko\Core\Path\ProjectPaths; readonly class CacheConfig { public function __construct( private ConfigRepositoryInterface $config, + private ?ProjectPaths $paths = null, ) {} public function driver(): string @@ -17,9 +19,19 @@ public function driver(): string return $this->config->getString('cache.driver'); } + /** + * A relative cache.path resolves against the project root, never getcwd(): + * FPM, CGI and mod_php chdir into public/ before running the front controller. + */ public function path(): string { - return $this->config->getString('cache.path'); + $path = $this->config->getString('cache.path'); + + if ($this->paths === null || str_starts_with($path, '/')) { + return $path; + } + + return $this->paths->base . '/' . $path; } public function defaultTtl(): int diff --git a/packages/cache/tests/Unit/CacheConfigTest.php b/packages/cache/tests/Unit/CacheConfigTest.php index 8a00fb111..8a2f4e34d 100644 --- a/packages/cache/tests/Unit/CacheConfigTest.php +++ b/packages/cache/tests/Unit/CacheConfigTest.php @@ -3,7 +3,10 @@ declare(strict_types=1); use Marko\Cache\Config\CacheConfig; +use Marko\Config\ConfigRepositoryInterface; use Marko\Config\Exceptions\ConfigNotFoundException; +use Marko\Core\Container\Container; +use Marko\Core\Path\ProjectPaths; use Marko\Testing\Fake\FakeConfigRepository; it('reads driver from config without fallback', function (): void { @@ -22,6 +25,35 @@ expect($config->path())->toBe('/var/cache'); }); +it('resolves a relative path against the project root, not the working directory', function (): void { + $config = new CacheConfig( + new FakeConfigRepository(['cache.path' => 'storage/cache']), + new ProjectPaths('/srv/app'), + ); + + expect($config->path())->toBe('/srv/app/storage/cache'); +}); + +it('gets the project root from the container', function (): void { + $container = new Container(); + $container->instance( + ConfigRepositoryInterface::class, + new FakeConfigRepository(['cache.path' => 'storage/cache']), + ); + $container->instance(ProjectPaths::class, new ProjectPaths('/srv/app')); + + expect($container->get(CacheConfig::class)->path())->toBe('/srv/app/storage/cache'); +}); + +it('keeps an absolute path as configured', function (): void { + $config = new CacheConfig( + new FakeConfigRepository(['cache.path' => '/var/cache']), + new ProjectPaths('/srv/app'), + ); + + expect($config->path())->toBe('/var/cache'); +}); + it('reads default_ttl from config without fallback', function (): void { $config = new CacheConfig(new FakeConfigRepository([ 'cache.default_ttl' => 7200,