Loading core/modules/layout_builder/src/Plugin/Block/FieldBlock.php +8 −2 Changes for core/modules/layout_builder/src/Plugin/Block/FieldBlock.php: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -204,8 +204,14 @@ protected function blockAccess(AccountInterface $account) { return $access; } // Check to see if the field has any values. if ($field->isEmpty()) { // Check to see if the field has any values or a default value. if ($field->isEmpty() && !$field->getFieldDefinition()->getDefaultValue($entity)) { // @todo Remove special handling of image fields after // https://www.drupal.org/project/drupal/issues/3005528. if ($field->getFieldDefinition()->getType() === 'image' && $field->getFieldDefinition()->getSetting('default_image')) { return $access; } return $access->andIf(AccessResult::forbidden()); } return $access; Loading core/modules/layout_builder/tests/src/Functional/LayoutBuilderDefaultValuesTest.php 0 → 100644 +295 −0 Changes for core/modules/layout_builder/tests/src/Functional/LayoutBuilderDefaultValuesTest.php: 295 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\file\Entity\File; use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\image\Kernel\ImageFieldCreationTrait; use Drupal\Tests\TestFileCreationTrait; /** * Tests rendering default field values in Layout Builder. * * @group layout_builder */ class LayoutBuilderDefaultValuesTest extends BrowserTestBase { use ImageFieldCreationTrait; use TestFileCreationTrait { getTestFiles as drupalGetTestFiles; } /** * {@inheritdoc} */ protected static $modules = [ 'layout_builder', 'block', 'node', 'image', ]; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->createContentType([ 'type' => 'test_node_type', 'name' => 'Test Node Type', ]); $this->addTextFields(); $this->addImageFields(); // Create node 1 with specific values. $this->createNode([ 'type' => 'test_node_type', 'title' => 'Test Node 1 Has Values', 'field_string_no_default' => 'No default, no problem.', 'field_string_with_default' => 'It is ok to be different', 'field_string_with_callback' => 'Not from a callback', 'field_string_late_default' => 'I am way ahead of you.', 'field_image_with_default' => [ 'target_id' => 2, 'alt' => 'My different alt text', ], 'field_image_no_default' => [ 'target_id' => 3, 'alt' => 'My third alt text', ], ]); // Create node 2 relying on defaults. $this->createNode([ 'type' => 'test_node_type', 'title' => 'Test Node 2 Uses Defaults', ]); // Add default value to field_string_late_default. $field = FieldConfig::loadByName('node', 'test_node_type', 'field_string_late_default'); $field->setDefaultValue('Too late!'); $field->save(); } /** * Tests display of default field values. */ public function testDefaultValues() { // Begin by viewing nodes with Layout Builder disabled. $this->assertNodeWithValues(); $this->assertNodeWithDefaultValues(); // Enable layout builder. LayoutBuilderEntityViewDisplay::load('node.test_node_type.default') ->enableLayoutBuilder() ->save(); // Confirm that default values are handled consistently by Layout Builder. $this->assertNodeWithValues(); $this->assertNodeWithDefaultValues(); } /** * Test for expected text on node 1. */ protected function assertNodeWithValues() { $this->drupalGet('node/1'); $assert_session = $this->assertSession(); // String field with no default should render a value. $assert_session->pageTextContains('field_string_no_default'); $assert_session->pageTextContains('No default, no problem.'); // String field with default should render non-default value. $assert_session->pageTextContains('field_string_with_default'); $assert_session->pageTextNotContains('This is my default value'); $assert_session->pageTextContains('It is ok to be different'); // String field with callback should render non-default value. $assert_session->pageTextContains('field_string_with_callback'); $assert_session->pageTextNotContains('This is from my default value callback'); $assert_session->pageTextContains('Not from a callback'); // String field with "late" default should render non-default value. $assert_session->pageTextContains('field_string_late_default'); $assert_session->pageTextNotContains('Too late!'); $assert_session->pageTextContains('I am way ahead of you'); // Image field with default should render non-default value. $assert_session->pageTextContains('field_image_with_default'); $assert_session->responseNotContains('My default alt text'); $assert_session->responseNotContains('test-file-1'); $assert_session->responseContains('My different alt text'); $assert_session->responseContains('test-file-2'); // Image field with no default should render a value. $assert_session->pageTextContains('field_image_no_default'); $assert_session->responseContains('My third alt text'); $assert_session->responseContains('test-file-3'); } /** * Test for expected text on node 2. */ protected function assertNodeWithDefaultValues() { $this->drupalGet('node/2'); $assert_session = $this->assertSession(); // String field with no default should not render. $assert_session->pageTextNotContains('field_string_no_default'); // String with default value should render with default value. $assert_session->pageTextContains('field_string'); $assert_session->pageTextContains('This is my default value'); // String field with callback should render value from callback. $assert_session->pageTextContains('field_string_with_callback'); $assert_session->pageTextContains('This is from my default value callback'); // String field with "late" default should not render. $assert_session->pageTextNotContains('field_string_late_default'); $assert_session->pageTextNotContains('Too late!'); // Image field with default should render default value. $assert_session->pageTextContains('field_image_with_default'); $assert_session->responseContains('My default alt text'); $assert_session->responseContains('test-file-1'); // Image field with no default should not render. $assert_session->pageTextNotContains('field_image_no_default'); } /** * Helper function to add string fields. */ protected function addTextFields() { // String field with no default. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_no_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->save(); // String field with default value. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_with_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->setDefaultValue('This is my default value'); $field->save(); // String field with default callback. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_with_callback', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->setDefaultValueCallback('Drupal\Tests\layout_builder\Functional\LayoutBuilderDefaultValuesTest::defaultValueCallback'); $field->save(); // String field with late default. We will set default later. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_late_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->save(); /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */ $display_repository = \Drupal::service('entity_display.repository'); $display_repository->getViewDisplay('node', 'test_node_type') ->setComponent('field_string_no_default', [ 'type' => 'string', ]) ->setComponent('field_string_with_default', [ 'type' => 'string', ]) ->setComponent('field_string_with_callback', [ 'type' => 'string', ]) ->setComponent('field_string_late_default', [ 'type' => 'string', ]) ->save(); } /** * Helper function to add image fields. */ protected function addImageFields() { // Create files to use as the default images. $files = $this->drupalGetTestFiles('image'); $images = []; for ($i = 1; $i <= 3; $i++) { $filename = "test-file-$i"; $desired_filepath = 'public://' . $filename; \Drupal::service('file_system')->copy($files[0]->uri, $desired_filepath, FileSystemInterface::EXISTS_ERROR); $file = File::create([ 'uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename, ]); $file->save(); $images[] = $file; } $field_name = 'field_image_with_default'; $storage_settings['default_image'] = [ 'uuid' => $images[0]->uuid(), 'alt' => 'My default alt text', 'title' => '', 'width' => 0, 'height' => 0, ]; $field_settings['default_image'] = [ 'uuid' => $images[0]->uuid(), 'alt' => 'My default alt text', 'title' => '', 'width' => 0, 'height' => 0, ]; $widget_settings = [ 'preview_image_style' => 'medium', ]; $this->createImageField($field_name, 'test_node_type', $storage_settings, $field_settings, $widget_settings); $field_name = 'field_image_no_default'; $storage_settings = []; $field_settings = []; $widget_settings = [ 'preview_image_style' => 'medium', ]; $this->createImageField($field_name, 'test_node_type', $storage_settings, $field_settings, $widget_settings); } /** * Sample 'default value' callback. */ public static function defaultValueCallback(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) { return [['value' => 'This is from my default value callback']]; } } core/modules/layout_builder/tests/src/Kernel/FieldBlockTest.php +12 −1 Changes for core/modules/layout_builder/tests/src/Kernel/FieldBlockTest.php: 12 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -152,7 +152,7 @@ public function testBlockAccessEntityAllowedFieldNotAllowed($expected, $field_ac * @covers ::build * @dataProvider providerTestBlockAccessEntityAllowedFieldHasValue */ public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty) { public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty, $default_value) { $entity = $this->prophesize(FieldableEntityInterface::class); $block = $this->getTestBlock($entity); Loading @@ -160,6 +160,10 @@ public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty) $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed()); $entity->hasField('the_field_name')->willReturn(TRUE); $field = $this->prophesize(FieldItemListInterface::class); $field_definition = $this->prophesize(FieldDefinitionInterface::class); $field->getFieldDefinition()->willReturn($field_definition->reveal()); $field_definition->getDefaultValue($entity->reveal())->willReturn($default_value); $field_definition->getType()->willReturn('not_an_image'); $entity->get('the_field_name')->willReturn($field->reveal()); $field->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed()); Loading @@ -177,10 +181,17 @@ public function providerTestBlockAccessEntityAllowedFieldHasValue() { $data['empty'] = [ FALSE, TRUE, FALSE, ]; $data['populated'] = [ TRUE, FALSE, FALSE, ]; $data['empty, with default'] = [ TRUE, TRUE, TRUE, ]; return $data; } Loading Loading
core/modules/layout_builder/src/Plugin/Block/FieldBlock.php +8 −2 Changes for core/modules/layout_builder/src/Plugin/Block/FieldBlock.php: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -204,8 +204,14 @@ protected function blockAccess(AccountInterface $account) { return $access; } // Check to see if the field has any values. if ($field->isEmpty()) { // Check to see if the field has any values or a default value. if ($field->isEmpty() && !$field->getFieldDefinition()->getDefaultValue($entity)) { // @todo Remove special handling of image fields after // https://www.drupal.org/project/drupal/issues/3005528. if ($field->getFieldDefinition()->getType() === 'image' && $field->getFieldDefinition()->getSetting('default_image')) { return $access; } return $access->andIf(AccessResult::forbidden()); } return $access; Loading
core/modules/layout_builder/tests/src/Functional/LayoutBuilderDefaultValuesTest.php 0 → 100644 +295 −0 Changes for core/modules/layout_builder/tests/src/Functional/LayoutBuilderDefaultValuesTest.php: 295 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\file\Entity\File; use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\image\Kernel\ImageFieldCreationTrait; use Drupal\Tests\TestFileCreationTrait; /** * Tests rendering default field values in Layout Builder. * * @group layout_builder */ class LayoutBuilderDefaultValuesTest extends BrowserTestBase { use ImageFieldCreationTrait; use TestFileCreationTrait { getTestFiles as drupalGetTestFiles; } /** * {@inheritdoc} */ protected static $modules = [ 'layout_builder', 'block', 'node', 'image', ]; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->createContentType([ 'type' => 'test_node_type', 'name' => 'Test Node Type', ]); $this->addTextFields(); $this->addImageFields(); // Create node 1 with specific values. $this->createNode([ 'type' => 'test_node_type', 'title' => 'Test Node 1 Has Values', 'field_string_no_default' => 'No default, no problem.', 'field_string_with_default' => 'It is ok to be different', 'field_string_with_callback' => 'Not from a callback', 'field_string_late_default' => 'I am way ahead of you.', 'field_image_with_default' => [ 'target_id' => 2, 'alt' => 'My different alt text', ], 'field_image_no_default' => [ 'target_id' => 3, 'alt' => 'My third alt text', ], ]); // Create node 2 relying on defaults. $this->createNode([ 'type' => 'test_node_type', 'title' => 'Test Node 2 Uses Defaults', ]); // Add default value to field_string_late_default. $field = FieldConfig::loadByName('node', 'test_node_type', 'field_string_late_default'); $field->setDefaultValue('Too late!'); $field->save(); } /** * Tests display of default field values. */ public function testDefaultValues() { // Begin by viewing nodes with Layout Builder disabled. $this->assertNodeWithValues(); $this->assertNodeWithDefaultValues(); // Enable layout builder. LayoutBuilderEntityViewDisplay::load('node.test_node_type.default') ->enableLayoutBuilder() ->save(); // Confirm that default values are handled consistently by Layout Builder. $this->assertNodeWithValues(); $this->assertNodeWithDefaultValues(); } /** * Test for expected text on node 1. */ protected function assertNodeWithValues() { $this->drupalGet('node/1'); $assert_session = $this->assertSession(); // String field with no default should render a value. $assert_session->pageTextContains('field_string_no_default'); $assert_session->pageTextContains('No default, no problem.'); // String field with default should render non-default value. $assert_session->pageTextContains('field_string_with_default'); $assert_session->pageTextNotContains('This is my default value'); $assert_session->pageTextContains('It is ok to be different'); // String field with callback should render non-default value. $assert_session->pageTextContains('field_string_with_callback'); $assert_session->pageTextNotContains('This is from my default value callback'); $assert_session->pageTextContains('Not from a callback'); // String field with "late" default should render non-default value. $assert_session->pageTextContains('field_string_late_default'); $assert_session->pageTextNotContains('Too late!'); $assert_session->pageTextContains('I am way ahead of you'); // Image field with default should render non-default value. $assert_session->pageTextContains('field_image_with_default'); $assert_session->responseNotContains('My default alt text'); $assert_session->responseNotContains('test-file-1'); $assert_session->responseContains('My different alt text'); $assert_session->responseContains('test-file-2'); // Image field with no default should render a value. $assert_session->pageTextContains('field_image_no_default'); $assert_session->responseContains('My third alt text'); $assert_session->responseContains('test-file-3'); } /** * Test for expected text on node 2. */ protected function assertNodeWithDefaultValues() { $this->drupalGet('node/2'); $assert_session = $this->assertSession(); // String field with no default should not render. $assert_session->pageTextNotContains('field_string_no_default'); // String with default value should render with default value. $assert_session->pageTextContains('field_string'); $assert_session->pageTextContains('This is my default value'); // String field with callback should render value from callback. $assert_session->pageTextContains('field_string_with_callback'); $assert_session->pageTextContains('This is from my default value callback'); // String field with "late" default should not render. $assert_session->pageTextNotContains('field_string_late_default'); $assert_session->pageTextNotContains('Too late!'); // Image field with default should render default value. $assert_session->pageTextContains('field_image_with_default'); $assert_session->responseContains('My default alt text'); $assert_session->responseContains('test-file-1'); // Image field with no default should not render. $assert_session->pageTextNotContains('field_image_no_default'); } /** * Helper function to add string fields. */ protected function addTextFields() { // String field with no default. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_no_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->save(); // String field with default value. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_with_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->setDefaultValue('This is my default value'); $field->save(); // String field with default callback. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_with_callback', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->setDefaultValueCallback('Drupal\Tests\layout_builder\Functional\LayoutBuilderDefaultValuesTest::defaultValueCallback'); $field->save(); // String field with late default. We will set default later. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_string_late_default', 'entity_type' => 'node', 'type' => 'string', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'test_node_type', ]); $field->save(); /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */ $display_repository = \Drupal::service('entity_display.repository'); $display_repository->getViewDisplay('node', 'test_node_type') ->setComponent('field_string_no_default', [ 'type' => 'string', ]) ->setComponent('field_string_with_default', [ 'type' => 'string', ]) ->setComponent('field_string_with_callback', [ 'type' => 'string', ]) ->setComponent('field_string_late_default', [ 'type' => 'string', ]) ->save(); } /** * Helper function to add image fields. */ protected function addImageFields() { // Create files to use as the default images. $files = $this->drupalGetTestFiles('image'); $images = []; for ($i = 1; $i <= 3; $i++) { $filename = "test-file-$i"; $desired_filepath = 'public://' . $filename; \Drupal::service('file_system')->copy($files[0]->uri, $desired_filepath, FileSystemInterface::EXISTS_ERROR); $file = File::create([ 'uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename, ]); $file->save(); $images[] = $file; } $field_name = 'field_image_with_default'; $storage_settings['default_image'] = [ 'uuid' => $images[0]->uuid(), 'alt' => 'My default alt text', 'title' => '', 'width' => 0, 'height' => 0, ]; $field_settings['default_image'] = [ 'uuid' => $images[0]->uuid(), 'alt' => 'My default alt text', 'title' => '', 'width' => 0, 'height' => 0, ]; $widget_settings = [ 'preview_image_style' => 'medium', ]; $this->createImageField($field_name, 'test_node_type', $storage_settings, $field_settings, $widget_settings); $field_name = 'field_image_no_default'; $storage_settings = []; $field_settings = []; $widget_settings = [ 'preview_image_style' => 'medium', ]; $this->createImageField($field_name, 'test_node_type', $storage_settings, $field_settings, $widget_settings); } /** * Sample 'default value' callback. */ public static function defaultValueCallback(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) { return [['value' => 'This is from my default value callback']]; } }
core/modules/layout_builder/tests/src/Kernel/FieldBlockTest.php +12 −1 Changes for core/modules/layout_builder/tests/src/Kernel/FieldBlockTest.php: 12 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -152,7 +152,7 @@ public function testBlockAccessEntityAllowedFieldNotAllowed($expected, $field_ac * @covers ::build * @dataProvider providerTestBlockAccessEntityAllowedFieldHasValue */ public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty) { public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty, $default_value) { $entity = $this->prophesize(FieldableEntityInterface::class); $block = $this->getTestBlock($entity); Loading @@ -160,6 +160,10 @@ public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty) $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed()); $entity->hasField('the_field_name')->willReturn(TRUE); $field = $this->prophesize(FieldItemListInterface::class); $field_definition = $this->prophesize(FieldDefinitionInterface::class); $field->getFieldDefinition()->willReturn($field_definition->reveal()); $field_definition->getDefaultValue($entity->reveal())->willReturn($default_value); $field_definition->getType()->willReturn('not_an_image'); $entity->get('the_field_name')->willReturn($field->reveal()); $field->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed()); Loading @@ -177,10 +181,17 @@ public function providerTestBlockAccessEntityAllowedFieldHasValue() { $data['empty'] = [ FALSE, TRUE, FALSE, ]; $data['populated'] = [ TRUE, FALSE, FALSE, ]; $data['empty, with default'] = [ TRUE, TRUE, TRUE, ]; return $data; } Loading