From d4de3a71afea24e90b21d2e65854e7442bdefb52 Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Tue, 20 Oct 2026 20:25:20 +0900 Subject: [PATCH 1/3] refactor: use ResolvesLocalDiskPaths for --in in MakeManualSiteNamesJson resolvePath() used base_path() directly, which only worked because the --in default option already includes the full storage/app/private/... prefix. Unlike every other console command in this pipeline, it could not accept a disk-relative path (e.g. --in=unesco/manual_input.txt), silently resolving it to the wrong location under the project root. ResolvesLocalDiskPaths::resolvePathToFile() handles both forms correctly and resolves to the identical path for the existing default option value. --- .../Commands/MakeManualSiteNamesJson.php | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/app/Console/Commands/MakeManualSiteNamesJson.php b/src/app/Console/Commands/MakeManualSiteNamesJson.php index f2093897..9c7c36f3 100644 --- a/src/app/Console/Commands/MakeManualSiteNamesJson.php +++ b/src/app/Console/Commands/MakeManualSiteNamesJson.php @@ -2,11 +2,14 @@ namespace App\Console\Commands; +use App\Console\Concerns\ResolvesLocalDiskPaths; use Illuminate\Console\Command; use Illuminate\Support\Facades\Storage; class MakeManualSiteNamesJson extends Command { + use ResolvesLocalDiskPaths; + protected $signature = 'world-heritage:make-manual-names-json {--in=storage/app/private/unesco/manual_input.txt : Input text file} {--out=storage/app/private/unesco/site_names_manual.json : Output JSON file} @@ -22,7 +25,7 @@ public function handle(): int $pretty = (bool) $this->option('pretty'); $strict = (bool) $this->option('strict'); - $inPath = $this->resolvePath($in); + $inPath = $this->resolvePathToFile($in); if (!is_file($inPath)) { $this->error("Input not found: {$inPath}"); return self::FAILURE; @@ -215,22 +218,6 @@ private function isSiteLine(string $line): bool return preg_match('/[\((]\s*\d{4}.*[\))]\s*$/u', $line) === 1; } - private function resolvePath(string $path): string - { - $path = trim($path); - if ($path === '') { - return $path; - } - if (str_starts_with($path, '/')) { - return $path; - } - if (preg_match('/^[A-Za-z]:\\\\/', $path) === 1) { - return $path; - } - - return base_path($path); - } - private function toLocalDiskPath(string $path): string { $trimPath = trim($path); From 84334fad6a4a3ce823386fcb5cfd833c0fc05d2f Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Tue, 20 Oct 2026 20:25:52 +0900 Subject: [PATCH 2/3] fix: avoid doubled private segment when writing MakeManualSiteNamesJson output toLocalDiskPath() only stripped the storage/app/ prefix, not private/. With the documented default --out value (storage/app/private/unesco/site_names_manual.json), the file actually landed at storage/app/private/private/unesco/site_names_manual.json on the local disk (root storage/app/private), while the log line claimed the correct single-private path. Switch to ResolvesLocalDiskPaths::normalizeLocalDiskPath(), which strips both prefixes, and log the real resolved path instead of a hardcoded "storage/app/" prefix assumption. --- .../Commands/MakeManualSiteNamesJson.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/app/Console/Commands/MakeManualSiteNamesJson.php b/src/app/Console/Commands/MakeManualSiteNamesJson.php index 9c7c36f3..9ff47165 100644 --- a/src/app/Console/Commands/MakeManualSiteNamesJson.php +++ b/src/app/Console/Commands/MakeManualSiteNamesJson.php @@ -90,14 +90,14 @@ public function handle(): int return self::FAILURE; } - $outDiskPath = $this->toLocalDiskPath($out); + $outDiskPath = $this->normalizeLocalDiskPath($out); if ($outDiskPath === '') { $this->error("Output path is empty."); return self::FAILURE; } Storage::disk('local')->put($outDiskPath, $json); - $this->info("Wrote: storage/app/{$outDiskPath} (count=" . count($rows) . ")"); + $this->info('Wrote: ' . Storage::disk('local')->path($outDiskPath) . ' (count=' . count($rows) . ')'); return self::SUCCESS; } @@ -218,17 +218,4 @@ private function isSiteLine(string $line): bool return preg_match('/[\((]\s*\d{4}.*[\))]\s*$/u', $line) === 1; } - private function toLocalDiskPath(string $path): string - { - $trimPath = trim($path); - if ($trimPath === '') { - return $trimPath; - } - - if (str_starts_with($trimPath, 'storage/app/')) { - return substr($trimPath, strlen('storage/app/')); - } - - return ltrim($trimPath, '/'); - } } From 420ef187d33cc1e022bf004f6858b390b74d26a0 Mon Sep 17 00:00:00 2001 From: Application-drop-up Date: Tue, 20 Oct 2026 20:25:56 +0900 Subject: [PATCH 3/3] test: cover MakeManualSiteNamesJson path resolution fixes Regression tests for both fixes: - --in now accepts a disk-relative path like every other command - --out no longer lands under a doubled private/ segment --- .../Tests/MakeManualSiteNamesJsonTest.php | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/app/Packages/Domains/WorldHeritage/Tests/MakeManualSiteNamesJsonTest.php diff --git a/src/app/Packages/Domains/WorldHeritage/Tests/MakeManualSiteNamesJsonTest.php b/src/app/Packages/Domains/WorldHeritage/Tests/MakeManualSiteNamesJsonTest.php new file mode 100644 index 00000000..13d1df9b --- /dev/null +++ b/src/app/Packages/Domains/WorldHeritage/Tests/MakeManualSiteNamesJsonTest.php @@ -0,0 +1,45 @@ +put('unesco/manual_input_test.txt', "Japan\nテストサイト (2000)\n"); + } + + public function test_accepts_disk_relative_input_path_like_other_commands(): void + { + Storage::fake('local'); + $this->writeInputFixture(); + + $exitCode = Artisan::call('world-heritage:make-manual-names-json', [ + '--in' => 'unesco/manual_input_test.txt', + '--out' => 'storage/app/private/unesco/manual_output_test.json', + ]); + + $this->assertSame(0, $exitCode); + } + + public function test_output_is_written_without_a_doubled_private_segment(): void + { + Storage::fake('local'); + $this->writeInputFixture(); + + Artisan::call('world-heritage:make-manual-names-json', [ + '--in' => 'storage/app/private/unesco/manual_input_test.txt', + '--out' => 'storage/app/private/unesco/manual_output_test.json', + ]); + + $this->assertTrue(Storage::disk('local')->exists('unesco/manual_output_test.json')); + $this->assertFalse(Storage::disk('local')->exists('private/unesco/manual_output_test.json')); + } +}