diff --git a/src/Fieldtypes/Assets/Assets.php b/src/Fieldtypes/Assets/Assets.php index d82286f4380..a99e2667d7c 100644 --- a/src/Fieldtypes/Assets/Assets.php +++ b/src/Fieldtypes/Assets/Assets.php @@ -238,27 +238,39 @@ public function preload() return [ 'data' => $this->getItemData($this->field->value() ?? $this->defaultValue), - 'container' => [ - 'id' => $container->id(), - 'title' => $container->title(), - 'edit_url' => $container->editUrl(), - 'delete_url' => $container->deleteUrl(), - 'blueprint_url' => cp_route('blueprints.asset-containers.edit', $container->handle()), - 'can_view' => User::current()->can('view', $container), - 'can_upload' => User::current()->can('store', [\Statamic\Contracts\Assets\Asset::class, $container]), - 'can_edit' => User::current()->can('edit', $container), - 'can_delete' => User::current()->can('delete', $container), - 'can_create_folders' => User::current()->can('create', [\Statamic\Contracts\Assets\AssetFolder::class, $container]), - 'sort_field' => $container->sortField(), - 'sort_direction' => $container->sortDirection(), - ], + 'container' => $this->containerForPreload($container), 'dynamicFolder' => $dynamicFolder = $this->dynamicFolder(), 'rename_folder' => $this->renameFolderAction($dynamicFolder), 'columns' => $this->getColumns(), ]; } + private function containerForPreload($container) + { + // It's the same for every assets field that uses the container, and a page can have a lot of them. + return Blink::once('assets-fieldtype-container-'.$container->handle().'-'.User::current()?->id(), fn () => [ + 'id' => $container->id(), + 'title' => $container->title(), + 'edit_url' => $container->editUrl(), + 'delete_url' => $container->deleteUrl(), + 'blueprint_url' => cp_route('blueprints.asset-containers.edit', $container->handle()), + 'can_view' => User::current()->can('view', $container), + 'can_upload' => User::current()->can('store', [\Statamic\Contracts\Assets\Asset::class, $container]), + 'can_edit' => User::current()->can('edit', $container), + 'can_delete' => User::current()->can('delete', $container), + 'can_create_folders' => User::current()->can('create', [\Statamic\Contracts\Assets\AssetFolder::class, $container]), + 'sort_field' => $container->sortField(), + 'sort_direction' => $container->sortDirection(), + ]); + } + protected function getColumns() + { + return Blink::once('assets-fieldtype-columns-'.$this->container()->handle().'-'.User::current()?->id(), fn () => $this->makeColumns()) + ->map(fn ($column) => clone $column); + } + + private function makeColumns() { $columns = $this->container()->blueprint()->columns()->map(fn ($column) => clone $column); diff --git a/tests/Fieldtypes/AssetsTest.php b/tests/Fieldtypes/AssetsTest.php index 590942b1786..ab7aac6beda 100644 --- a/tests/Fieldtypes/AssetsTest.php +++ b/tests/Fieldtypes/AssetsTest.php @@ -24,6 +24,7 @@ class AssetsTest extends TestCase { use PreventSavingStacheItemsToDisk; + use \Tests\FakesRoles; use TestsQueryableValueWithMaxItems; public function setUp(): void @@ -257,6 +258,54 @@ public function it_doesnt_replace_non_image_related_rule() $this->assertEquals('file', $replaced[0]); } + #[Test] + public function what_it_preloads_about_a_container_is_worked_out_once_however_many_fields_use_it() + { + $this->setTestRoles(['test' => ['access cp', 'view test assets']]); + $this->actingAs(tap(\Statamic\Facades\User::make()->assignRole('test'))->save()); + + $checks = 0; + \Illuminate\Support\Facades\Gate::after(function () use (&$checks) { + $checks++; + }); + + $first = $this->fieldtype(['container' => 'test'])->preload(); + $checksForOne = $checks; + $second = $this->fieldtype(['container' => 'test'])->preload(); + + $this->assertGreaterThan(0, $checksForOne); + $this->assertSame($checksForOne, $checks); + $this->assertSame($first['container'], $second['container']); + $this->assertTrue($first['container']['can_view']); + $this->assertFalse($first['container']['can_delete']); + $this->assertEquals($first['columns']->map->toArray()->all(), $second['columns']->map->toArray()->all()); + } + + #[Test] + public function each_field_gets_columns_of_its_own() + { + $this->actingAs(tap(\Statamic\Facades\User::make()->makeSuper())->save()); + + $first = $this->fieldtype(['container' => 'test'])->preload()['columns']; + $first->first()->label('Changed'); + $second = $this->fieldtype(['container' => 'test'])->preload()['columns']; + + $this->assertNotSame($first->first(), $second->first()); + $this->assertSame('Alt Text', $second->first()->label()); + } + + #[Test] + public function what_it_preloads_about_a_container_is_each_users_own() + { + $this->setTestRoles(['test' => ['access cp', 'view test assets']]); + + $this->actingAs(tap(\Statamic\Facades\User::make()->id('one')->assignRole('test'))->save()); + $this->assertFalse($this->fieldtype(['container' => 'test'])->preload()['container']['can_edit']); + + $this->actingAs(tap(\Statamic\Facades\User::make()->id('two')->makeSuper())->save()); + $this->assertTrue($this->fieldtype(['container' => 'test'])->preload()['container']['can_edit']); + } + public function fieldtype($config = []) { return (new Assets)->setField(new Field('test', array_merge([