From dc340aee4a6a71f5b525762f71ac55b90ad920a7 Mon Sep 17 00:00:00 2001 From: Peiman Nourani Date: Thu, 9 May 2024 19:52:59 +0100 Subject: [PATCH 1/8] prevent some folders from listing in template FT --- src/Fieldtypes/TemplateFolder.php | 22 +++++++++++++++---- .../CP/API/TemplatesController.php | 16 +++++++++++++- .../CP/Collections/CollectionsController.php | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/Fieldtypes/TemplateFolder.php b/src/Fieldtypes/TemplateFolder.php index 217c426c936..6852aead7cc 100644 --- a/src/Fieldtypes/TemplateFolder.php +++ b/src/Fieldtypes/TemplateFolder.php @@ -2,6 +2,8 @@ namespace Statamic\Fieldtypes; +use FilesystemIterator; +use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use Statamic\Support\Str; @@ -21,12 +23,24 @@ public function getIndexItems($request) return collect(config('view.paths')) ->flatMap(function ($path) { $directories = collect(); - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST); + $filter = ['.git', 'node_modules']; + + $iterator = new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator( + $path, + FilesystemIterator::SKIP_DOTS + + ), + function ($fileInfo, $key, $iterator) use ($filter) { + return ! $iterator->isLink() && $fileInfo->isDir() && ! in_array($fileInfo->getBaseName(), $filter); + } + ), + RecursiveIteratorIterator::SELF_FIRST + ); foreach ($iterator as $file) { - if ($file->isDir() && ! $iterator->isDot() && ! $iterator->isLink()) { - $directories->push(Str::replaceFirst($path.DIRECTORY_SEPARATOR, '', $file->getPathname())); - } + $directories->push(Str::replaceFirst($path.DIRECTORY_SEPARATOR, '', $file->getPathname())); } return $directories->filter()->values(); diff --git a/src/Http/Controllers/CP/API/TemplatesController.php b/src/Http/Controllers/CP/API/TemplatesController.php index fc42c5d7326..8f59bab6032 100644 --- a/src/Http/Controllers/CP/API/TemplatesController.php +++ b/src/Http/Controllers/CP/API/TemplatesController.php @@ -2,6 +2,8 @@ namespace Statamic\Http\Controllers\CP\API; +use FilesystemIterator; +use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use Statamic\Http\Controllers\CP\CpController; @@ -14,7 +16,19 @@ public function index() return collect(config('view.paths')) ->flatMap(function ($path) { $views = collect(); - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); + $filter = ['.git', 'node_modules']; + + $iterator = new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator( + $path, + FilesystemIterator::SKIP_DOTS + ), + function ($fileInfo, $key, $iterator) use ($filter) { + return $fileInfo->isFile() || ! in_array($fileInfo->getBaseName(), $filter); + } + ) + ); foreach ($iterator as $file) { if ($file->isFile()) { diff --git a/src/Http/Controllers/CP/Collections/CollectionsController.php b/src/Http/Controllers/CP/Collections/CollectionsController.php index 070ee05c6ea..72fa842f5f8 100644 --- a/src/Http/Controllers/CP/Collections/CollectionsController.php +++ b/src/Http/Controllers/CP/Collections/CollectionsController.php @@ -447,11 +447,13 @@ protected function editFormBlueprint($collection) 'type' => 'template', 'placeholder' => __('System default'), 'blueprint' => true, + 'folder' => 'templates', ], 'layout' => [ 'display' => __('Layout'), 'instructions' => __('statamic::messages.collection_configure_layout_instructions'), 'type' => 'template', + 'folder' => 'layouts', ], 'title_formats' => [ 'display' => __('Title Format'), From 6e333752973149f6d220aeb70dea759cdb974e00 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 10:08:18 -0400 Subject: [PATCH 2/8] not everyone stores their views like this. --- src/Http/Controllers/CP/Collections/CollectionsController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/CollectionsController.php b/src/Http/Controllers/CP/Collections/CollectionsController.php index e5bca2a33a0..4dc5622c1ce 100644 --- a/src/Http/Controllers/CP/Collections/CollectionsController.php +++ b/src/Http/Controllers/CP/Collections/CollectionsController.php @@ -447,13 +447,11 @@ protected function editFormBlueprint($collection) 'type' => 'template', 'placeholder' => __('System default'), 'blueprint' => true, - 'folder' => 'templates', ], 'layout' => [ 'display' => __('Layout'), 'instructions' => __('statamic::messages.collection_configure_layout_instructions'), 'type' => 'template', - 'folder' => 'layouts', ], 'title_formats' => [ 'display' => __('Title Format'), From 463ed9b014d86a742fbdaeea7a02cd925f32c0c6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 11:48:44 -0400 Subject: [PATCH 3/8] better tests, fix issues, and clean up. --- src/Fieldtypes/TemplateFolder.php | 36 ++------ .../CP/API/TemplatesController.php | 45 +++------- tests/Fieldtypes/TemplateFolderTest.php | 90 +++++++++++++++++++ tests/Fieldtypes/TemplatesTest.php | 59 ++++++++++-- 4 files changed, 163 insertions(+), 67 deletions(-) create mode 100644 tests/Fieldtypes/TemplateFolderTest.php diff --git a/src/Fieldtypes/TemplateFolder.php b/src/Fieldtypes/TemplateFolder.php index 6852aead7cc..b5432d6c5f1 100644 --- a/src/Fieldtypes/TemplateFolder.php +++ b/src/Fieldtypes/TemplateFolder.php @@ -20,32 +20,14 @@ protected function toItemArray($id, $site = null) public function getIndexItems($request) { - return collect(config('view.paths')) - ->flatMap(function ($path) { - $directories = collect(); - $filter = ['.git', 'node_modules']; - - $iterator = new RecursiveIteratorIterator( - new RecursiveCallbackFilterIterator( - new RecursiveDirectoryIterator( - $path, - FilesystemIterator::SKIP_DOTS - - ), - function ($fileInfo, $key, $iterator) use ($filter) { - return ! $iterator->isLink() && $fileInfo->isDir() && ! in_array($fileInfo->getBaseName(), $filter); - } - ), - RecursiveIteratorIterator::SELF_FIRST - ); - - foreach ($iterator as $file) { - $directories->push(Str::replaceFirst($path.DIRECTORY_SEPARATOR, '', $file->getPathname())); - } - - return $directories->filter()->values(); - }) - ->map(fn ($folder) => ['id' => $folder, 'title' => $folder]) - ->values(); + return collect(config('view.paths'))->flatMap(function ($path) { + return collect(new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + fn ($file) => $file->isDir() && ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) + ), + RecursiveIteratorIterator::SELF_FIRST + ))->map(fn ($file) => Str::of($file->getPathname())->after($path.DIRECTORY_SEPARATOR)); + })->map(fn ($folder) => ['id' => $folder, 'title' => $folder])->values(); } } diff --git a/src/Http/Controllers/CP/API/TemplatesController.php b/src/Http/Controllers/CP/API/TemplatesController.php index 8f59bab6032..a513f2e14ea 100644 --- a/src/Http/Controllers/CP/API/TemplatesController.php +++ b/src/Http/Controllers/CP/API/TemplatesController.php @@ -2,7 +2,6 @@ namespace Statamic\Http\Controllers\CP\API; -use FilesystemIterator; use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; @@ -13,37 +12,17 @@ class TemplatesController extends CpController { public function index() { - return collect(config('view.paths')) - ->flatMap(function ($path) { - $views = collect(); - $filter = ['.git', 'node_modules']; - - $iterator = new RecursiveIteratorIterator( - new RecursiveCallbackFilterIterator( - new RecursiveDirectoryIterator( - $path, - FilesystemIterator::SKIP_DOTS - ), - function ($fileInfo, $key, $iterator) use ($filter) { - return $fileInfo->isFile() || ! in_array($fileInfo->getBaseName(), $filter); - } - ) - ); - - foreach ($iterator as $file) { - if ($file->isFile()) { - $viewPath = Str::of($file->getPathname()) - ->after($path.DIRECTORY_SEPARATOR) - ->before('.') - ->replace('\\', '/') - ->toString(); - - $views->push($viewPath); - } - } - - return $views->filter()->sort()->values(); - }) - ->values(); + return collect(config('view.paths'))->flatMap(function ($path) { + return collect(new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), + fn ($file) => ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) + ) + ))->map(fn ($file) => Str::of($file->getPathname()) + ->after($path.DIRECTORY_SEPARATOR) + ->before('.') + ->replace('\\', '/') + )->sort()->values(); + }); } } diff --git a/tests/Fieldtypes/TemplateFolderTest.php b/tests/Fieldtypes/TemplateFolderTest.php new file mode 100644 index 00000000000..6aa3d7eee84 --- /dev/null +++ b/tests/Fieldtypes/TemplateFolderTest.php @@ -0,0 +1,90 @@ +makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); + + $this->app['config']->set('view.paths', [$this->dir]); + } + + public function tearDown(): void + { + app('files')->deleteDirectory($this->dir); + + parent::tearDown(); + } + + /** @test */ + public function it_returns_a_list_of_directories() + { + $this->createFiles(); + + $fieldtype = $this->fieldtype(); + + $items = $fieldtype->getIndexItems(request()); + + // A collection with identical id/title keys are returned but we're only really concerned about the content. + $actual = $items->map->id->all(); + + $this->assertEquals([ + 'empty', + 'one', + 'one/two', + ], $actual); + } + + private function createFiles() + { + $files = [ + // Regular files, these should all be shown. + 'alfa.html', + 'one/bravo.html', + 'one/two/charlie.html', + 'one/two/delta.html', + + // .git directories at any level should get filtered out + '.git/echo.html', + 'one/.git/foxtrot.html', + 'one/two/.git/golf.html', + + // node_modules at any level should get filtered out + 'node_modules/hotel.html', + 'one/node_modules/india.html', + 'one/two/node_modules/juliett.html', + + // dotfiles at any level should get filtered out + '.kilo.html', + 'one/.lima.html', + 'one/two/.mike.html', + ]; + + foreach ($files as $path) { + File::put($this->dir.'/'.$path, ''); + } + + // Empty directories should also be shown. + File::makeDirectory($this->dir.'/empty'); + } + + private function fieldtype() + { + $field = new Field('test', array_merge([ + 'type' => 'template_folder', + ])); + + return (new TemplateFolder)->setField($field); + } +} diff --git a/tests/Fieldtypes/TemplatesTest.php b/tests/Fieldtypes/TemplatesTest.php index 5848c325f39..0b0a1bf8375 100644 --- a/tests/Fieldtypes/TemplatesTest.php +++ b/tests/Fieldtypes/TemplatesTest.php @@ -2,6 +2,7 @@ namespace Tests\Fieldtypes; +use Statamic\Facades\File; use Statamic\Facades\User; use Tests\PreventSavingStacheItemsToDisk; use Tests\TestCase; @@ -10,26 +11,70 @@ class TemplatesTest extends TestCase { use PreventSavingStacheItemsToDisk; + private string $dir; + public function setUp(): void { parent::setUp(); - $this->app['config']->set('view.paths', [ - __DIR__.'/../__fixtures__/templates', - ]); + app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); + + $this->app['config']->set('view.paths', [$this->dir]); + } + + public function tearDown(): void + { + app('files')->deleteDirectory($this->dir); + + parent::tearDown(); } /** @test */ public function it_returns_a_list_of_templates() { + $files = [ + // Regular files, these should all be shown. + 'alfa.html', + 'one/bravo.html', + 'one/two/charlie.html', + 'one/two/delta.html', + + // .git directories at any level should get filtered out + '.git/echo.html', + 'one/.git/foxtrot.html', + 'one/two/.git/golf.html', + + // node_modules at any level should get filtered out + 'node_modules/hotel.html', + 'one/node_modules/india.html', + 'one/two/node_modules/juliett.html', + + // dot directories at any level should get filtered out + '.kilo/lima.html', + 'one/.mike/november.html', + 'one/two/.oscar/papa.html', + + // dotfiles at any level should get filtered out + '.quebec.html', + 'one/.rome.html', + 'one/two/.sierra.html', + ]; + + foreach ($files as $path) { + File::put($this->dir.'/'.$path, ''); + } + + // Empty directories should be ignored. + File::makeDirectory($this->dir.'/empty'); + $this ->actingAs(User::make()->makeSuper()->save()) ->get(cp_route('api.templates.index')) ->assertJson([ - 'blog/index', - 'conditions-literals', - 'five_hundred_nested_ifs', - 'nested-conditionals', + 'alfa', + 'one/bravo', + 'one/two/charlie', + 'one/two/delta', ]); } } From 53dda2c22d634dc08189b5a5b4694f3ba2f851f6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 12:09:41 -0400 Subject: [PATCH 4/8] handle symlinks --- src/Fieldtypes/TemplateFolder.php | 4 ++-- .../CP/API/TemplatesController.php | 2 +- tests/Fieldtypes/TemplateFolderTest.php | 24 ++++++++++++++++--- tests/Fieldtypes/TemplatesTest.php | 22 ++++++++++++++--- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/Fieldtypes/TemplateFolder.php b/src/Fieldtypes/TemplateFolder.php index b5432d6c5f1..f5878d119d7 100644 --- a/src/Fieldtypes/TemplateFolder.php +++ b/src/Fieldtypes/TemplateFolder.php @@ -23,11 +23,11 @@ public function getIndexItems($request) return collect(config('view.paths'))->flatMap(function ($path) { return collect(new RecursiveIteratorIterator( new RecursiveCallbackFilterIterator( - new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS), fn ($file) => $file->isDir() && ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) ), RecursiveIteratorIterator::SELF_FIRST ))->map(fn ($file) => Str::of($file->getPathname())->after($path.DIRECTORY_SEPARATOR)); - })->map(fn ($folder) => ['id' => $folder, 'title' => $folder])->values(); + })->map(fn ($folder) => ['id' => $folder, 'title' => $folder])->sort()->values(); } } diff --git a/src/Http/Controllers/CP/API/TemplatesController.php b/src/Http/Controllers/CP/API/TemplatesController.php index a513f2e14ea..7ed3fde0f34 100644 --- a/src/Http/Controllers/CP/API/TemplatesController.php +++ b/src/Http/Controllers/CP/API/TemplatesController.php @@ -15,7 +15,7 @@ public function index() return collect(config('view.paths'))->flatMap(function ($path) { return collect(new RecursiveIteratorIterator( new RecursiveCallbackFilterIterator( - new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), + new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::FOLLOW_SYMLINKS), fn ($file) => ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) ) ))->map(fn ($file) => Str::of($file->getPathname()) diff --git a/tests/Fieldtypes/TemplateFolderTest.php b/tests/Fieldtypes/TemplateFolderTest.php index 6aa3d7eee84..87eda5ca8e3 100644 --- a/tests/Fieldtypes/TemplateFolderTest.php +++ b/tests/Fieldtypes/TemplateFolderTest.php @@ -17,7 +17,7 @@ public function setUp(): void app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); - $this->app['config']->set('view.paths', [$this->dir]); + $this->app['config']->set('view.paths', [$this->dir.'/views']); } public function tearDown(): void @@ -41,8 +41,13 @@ public function it_returns_a_list_of_directories() $this->assertEquals([ 'empty', + 'empty-symlink', + 'empty-symlink/three', 'one', 'one/two', + 'symlink-dir', + 'symlink-dir/five', + 'symlink-dir/four', ], $actual); } @@ -72,11 +77,24 @@ private function createFiles() ]; foreach ($files as $path) { - File::put($this->dir.'/'.$path, ''); + File::put($this->dir.'/views/'.$path, ''); } // Empty directories should also be shown. - File::makeDirectory($this->dir.'/empty'); + File::makeDirectory($this->dir.'/views/empty'); + + // Symlinked directories (even empties) should be shown. + File::makeDirectory($this->dir.'/empty-symlink-target'); + File::makeDirectory($this->dir.'/empty-symlink-target/three'); + File::put($this->dir.'/symlink-target-dir/tango.html', ''); + File::put($this->dir.'/symlink-target-dir/four/uniform.html', ''); + File::makeDirectory($this->dir.'/symlink-target-dir/five'); + app('files')->link($this->dir.'/empty-symlink-target', $this->dir.'/views/empty-symlink'); + app('files')->link($this->dir.'/symlink-target-dir', $this->dir.'/views/symlink-dir'); + + // Symlinked files should not. + File::put($this->dir.'/foo.html', ''); + app('files')->link($this->dir.'/foo.html', $this->dir.'/views/victor.html'); } private function fieldtype() diff --git a/tests/Fieldtypes/TemplatesTest.php b/tests/Fieldtypes/TemplatesTest.php index 0b0a1bf8375..7565654b04c 100644 --- a/tests/Fieldtypes/TemplatesTest.php +++ b/tests/Fieldtypes/TemplatesTest.php @@ -19,7 +19,7 @@ public function setUp(): void app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); - $this->app['config']->set('view.paths', [$this->dir]); + $this->app['config']->set('view.paths', [$this->dir.'/views']); } public function tearDown(): void @@ -61,11 +61,24 @@ public function it_returns_a_list_of_templates() ]; foreach ($files as $path) { - File::put($this->dir.'/'.$path, ''); + File::put($this->dir.'/views/'.$path, ''); } // Empty directories should be ignored. - File::makeDirectory($this->dir.'/empty'); + File::makeDirectory($this->dir.'/views/empty'); + + // Empty symlinked directories should be ignored. + File::makeDirectory($this->dir.'/empty-symlink-target'); + app('files')->link($this->dir.'/empty-symlink-target', $this->dir.'/views/empty-symlink'); + + // Files in symlinked directories should be shown. + File::put($this->dir.'/symlink-target-dir/tango.html', ''); + File::put($this->dir.'/symlink-target-dir/three/uniform.html', ''); + app('files')->link($this->dir.'/symlink-target-dir', $this->dir.'/views/symlink-dir'); + + // Symlinked files should be shown. + File::put($this->dir.'/foo.html', ''); + app('files')->link($this->dir.'/foo.html', $this->dir.'/views/victor.html'); $this ->actingAs(User::make()->makeSuper()->save()) @@ -75,6 +88,9 @@ public function it_returns_a_list_of_templates() 'one/bravo', 'one/two/charlie', 'one/two/delta', + 'symlink-dir/tango', + 'symlink-dir/three/uniform', + 'victor', ]); } } From fd379a20263e3ef561d1dc31fa282563d9747a96 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 12:23:18 -0400 Subject: [PATCH 5/8] hush --- tests/Fieldtypes/TemplateFolderTest.php | 2 +- tests/Fieldtypes/TemplatesTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Fieldtypes/TemplateFolderTest.php b/tests/Fieldtypes/TemplateFolderTest.php index 87eda5ca8e3..afddfa8a0f8 100644 --- a/tests/Fieldtypes/TemplateFolderTest.php +++ b/tests/Fieldtypes/TemplateFolderTest.php @@ -15,7 +15,7 @@ public function setUp(): void { parent::setUp(); - app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); + app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp', force: true); $this->app['config']->set('view.paths', [$this->dir.'/views']); } diff --git a/tests/Fieldtypes/TemplatesTest.php b/tests/Fieldtypes/TemplatesTest.php index 7565654b04c..4c55f7d3db3 100644 --- a/tests/Fieldtypes/TemplatesTest.php +++ b/tests/Fieldtypes/TemplatesTest.php @@ -17,7 +17,7 @@ public function setUp(): void { parent::setUp(); - app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp'); + app('files')->makeDirectory($this->dir = __DIR__.'/templates-test-tmp', force: true); $this->app['config']->set('view.paths', [$this->dir.'/views']); } From 582d4829043399455fcdfb6bd852a54f498294ef Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 12:24:00 -0400 Subject: [PATCH 6/8] tostring so the failure is readable --- src/Fieldtypes/TemplateFolder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fieldtypes/TemplateFolder.php b/src/Fieldtypes/TemplateFolder.php index f5878d119d7..1acbbdd5b88 100644 --- a/src/Fieldtypes/TemplateFolder.php +++ b/src/Fieldtypes/TemplateFolder.php @@ -27,7 +27,7 @@ public function getIndexItems($request) fn ($file) => $file->isDir() && ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) ), RecursiveIteratorIterator::SELF_FIRST - ))->map(fn ($file) => Str::of($file->getPathname())->after($path.DIRECTORY_SEPARATOR)); + ))->map(fn ($file) => Str::of($file->getPathname())->after($path.DIRECTORY_SEPARATOR)->toString()); })->map(fn ($folder) => ['id' => $folder, 'title' => $folder])->sort()->values(); } } From 896367c57c247049f357234166a07f23d2103ae0 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 24 May 2024 12:38:37 -0400 Subject: [PATCH 7/8] replace slashes for windows --- src/Fieldtypes/TemplateFolder.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Fieldtypes/TemplateFolder.php b/src/Fieldtypes/TemplateFolder.php index 1acbbdd5b88..d7002c87668 100644 --- a/src/Fieldtypes/TemplateFolder.php +++ b/src/Fieldtypes/TemplateFolder.php @@ -27,7 +27,11 @@ public function getIndexItems($request) fn ($file) => $file->isDir() && ! str_starts_with($file->getFilename(), '.') && ! in_array($file->getBaseName(), ['node_modules']) ), RecursiveIteratorIterator::SELF_FIRST - ))->map(fn ($file) => Str::of($file->getPathname())->after($path.DIRECTORY_SEPARATOR)->toString()); + ))->map(fn ($file) => Str::of($file->getPathname()) + ->after($path.DIRECTORY_SEPARATOR) + ->replace('\\', '/') + ->toString() + ); })->map(fn ($folder) => ['id' => $folder, 'title' => $folder])->sort()->values(); } } From f41cde8baf8dcaf7fd617060288497971bd9c1b3 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Mon, 27 May 2024 11:03:39 -0400 Subject: [PATCH 8/8] fix test on windows --- tests/Fieldtypes/TemplateFolderTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Fieldtypes/TemplateFolderTest.php b/tests/Fieldtypes/TemplateFolderTest.php index afddfa8a0f8..cb1ed2d26f6 100644 --- a/tests/Fieldtypes/TemplateFolderTest.php +++ b/tests/Fieldtypes/TemplateFolderTest.php @@ -89,12 +89,12 @@ private function createFiles() File::put($this->dir.'/symlink-target-dir/tango.html', ''); File::put($this->dir.'/symlink-target-dir/four/uniform.html', ''); File::makeDirectory($this->dir.'/symlink-target-dir/five'); - app('files')->link($this->dir.'/empty-symlink-target', $this->dir.'/views/empty-symlink'); - app('files')->link($this->dir.'/symlink-target-dir', $this->dir.'/views/symlink-dir'); + symlink($this->dir.'/empty-symlink-target', $this->dir.'/views/empty-symlink'); + symlink($this->dir.'/symlink-target-dir', $this->dir.'/views/symlink-dir'); // Symlinked files should not. File::put($this->dir.'/foo.html', ''); - app('files')->link($this->dir.'/foo.html', $this->dir.'/views/victor.html'); + symlink($this->dir.'/foo.html', $this->dir.'/views/victor.html'); } private function fieldtype()