Loading core/modules/layout_builder/src/Field/LayoutSectionItemList.php +10 −0 Changes for core/modules/layout_builder/src/Field/LayoutSectionItemList.php: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,8 +2,10 @@ namespace Drupal\layout_builder\Field; use Drupal\Core\Access\AccessResult; use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Session\AccountInterface; use Drupal\layout_builder\Section; use Drupal\layout_builder\SectionListInterface; use Drupal\layout_builder\SectionStorage\SectionStorageTrait; Loading Loading @@ -74,4 +76,12 @@ public function equals(FieldItemListInterface $list_to_compare) { return $convert($this) === $convert($list_to_compare); } /** * {@inheritdoc} */ public function defaultAccess($operation = 'view', AccountInterface $account = NULL) { // @todo Allow access in https://www.drupal.org/node/2942975. return AccessResult::forbidden(); } } core/modules/layout_builder/src/LayoutBuilderServiceProvider.php +10 −0 Changes for core/modules/layout_builder/src/LayoutBuilderServiceProvider.php: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -5,6 +5,8 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\layout_builder\EventSubscriber\SetInlineBlockDependency; use Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; Loading Loading @@ -35,6 +37,14 @@ public function register(ContainerBuilder $container) { $definition->addTag('event_subscriber'); $container->setDefinition('layout_builder.get_block_dependency_subscriber', $definition); } if (isset($modules['serialization'])) { $definition = (new ChildDefinition('serializer.normalizer.config_entity')) ->setClass(LayoutEntityDisplayNormalizer::class) // Ensure that this normalizer takes precedence for Layout Builder data // over the generic serializer.normalizer.config_entity. ->addTag('normalizer', ['priority' => 5]); $container->setDefinition('layout_builder.normalizer.layout_entity_display', $definition); } } } core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php 0 → 100644 +33 −0 Changes for core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php: 33 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\layout_builder\Normalizer; use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; use Drupal\serialization\Normalizer\ConfigEntityNormalizer; /** * Normalizes/denormalizes LayoutEntityDisplay objects into an array structure. * * @internal * All tagged services are internal. */ class LayoutEntityDisplayNormalizer extends ConfigEntityNormalizer { /** * {@inheritdoc} */ protected $supportedInterfaceOrClass = LayoutEntityDisplayInterface::class; /** * {@inheritdoc} */ protected static function getDataWithoutInternals(array $data) { $data = parent::getDataWithoutInternals($data); // Do not expose the actual layout sections in normalization. // @todo Determine what to expose here in // https://www.drupal.org/node/2942975. unset($data['third_party_settings']['layout_builder']['sections']); return $data; } } core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySectionsTest.php 0 → 100644 +61 −0 Changes for core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySectionsTest.php: 61 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional\Rest; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Url; /** * Tests that default layout sections are not exposed via the REST API. * * @group layout_builder * @group rest */ class EntityDisplaySectionsTest extends LayoutRestTestBase { /** * {@inheritdoc} */ protected static $resourceConfigId = 'entity.entity_view_display'; /** * Tests the normalization does not contain layout sections. */ public function testLayoutEntityDisplay() { $display_id = 'node.bundle_with_section_field.default'; $display = EntityViewDisplay::load($display_id); // Assert the display has 1 section. $this->assertCount(1, $display->getThirdPartySetting('layout_builder', 'sections')); $response = $this->request( 'GET', Url::fromRoute( 'rest.entity.entity_view_display.GET', ['entity_view_display' => 'node.bundle_with_section_field.default']) ); $this->assertResourceResponse( 200, FALSE, $response, [ 'config:core.entity_view_display.node.bundle_with_section_field.default', 'config:rest.resource.entity.entity_view_display', 'config:rest.settings', 'http_response', ], [ 'user.permissions', ], FALSE, 'MISS' ); $response_data = $this->getDecodedContents($response); $this->assertSame($display_id, $response_data['id']); // Ensure the sections are not present in the serialized data, but other // Layout Builder data is. $this->assertArrayHasKey('layout_builder', $response_data['third_party_settings']); $this->assertArrayNotHasKey('sections', $response_data['third_party_settings']['layout_builder']); $this->assertEquals(['enabled' => TRUE, 'allow_custom' => TRUE], $response_data['third_party_settings']['layout_builder']); } } core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php 0 → 100644 +154 −0 Changes for core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php: 154 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional\Rest; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Url; use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait; use Drupal\Tests\rest\Functional\ResourceTestBase; use GuzzleHttp\RequestOptions; use Psr\Http\Message\ResponseInterface; /** * Base class for Layout Builder REST tests. */ abstract class LayoutRestTestBase extends ResourceTestBase { use BasicAuthResourceTestTrait; /** * {@inheritdoc} */ public static $modules = [ 'node', 'layout_builder', 'serialization', 'basic_auth', ]; /** * A test node. * * @var \Drupal\node\NodeInterface */ protected $node; /** * The node storage. * * @var \Drupal\node\NodeStorageInterface */ protected $nodeStorage; /** * {@inheritdoc} */ public function setUp() { parent::setUp(); $assert_session = $this->assertSession(); // @todo The Layout Builder UI relies on local tasks; fix in // https://www.drupal.org/project/drupal/issues/2917777. $this->drupalPlaceBlock('local_tasks_block'); $this->createContentType(['type' => 'bundle_with_section_field']); $this->drupalLogin($this->drupalCreateUser([ 'configure any layout', 'administer node display', 'administer display modes', 'bypass node access', 'create bundle_with_section_field content', 'edit any bundle_with_section_field content', ])); $page = $this->getSession()->getPage(); $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field/display'; // Enable Layout Builder for the default view modes, and overrides. $this->drupalGet("$field_ui_prefix/default"); $page->checkField('layout[enabled]'); $page->pressButton('Save'); $page->checkField('layout[allow_custom]'); $page->pressButton('Save'); // Create a node. $this->node = $this->createNode([ 'type' => 'bundle_with_section_field', 'title' => 'A node at rest will stay at rest.', ]); $this->drupalGet('node/' . $this->node->id() . '/layout'); $page->clickLink('Layout'); $page->clickLink('Add Block'); $page->clickLink('Powered by Drupal'); $page->fillField('settings[label]', 'This is an override'); $page->checkField('settings[label_display]'); $page->pressButton('Add Block'); $page->clickLink('Save Layout'); $assert_session->pageTextContains('This is an override'); $this->nodeStorage = $this->container->get('entity_type.manager')->getStorage('node'); $this->node = $this->nodeStorage->load($this->node->id()); $this->drupalLogout(); $this->setUpAuthorization('ALL'); $this->provisionResource([static::$format], ['basic_auth']); } /** * {@inheritdoc} */ protected function request($method, Url $url, array $request_options = []) { $request_options[RequestOptions::HEADERS] = [ 'Content-Type' => static::$mimeType, ]; $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions($method)); $request_options[RequestOptions::QUERY] = ['_format' => static::$format]; return parent::request($method, $url, $request_options); } /** * {@inheritdoc} */ protected function setUpAuthorization($method) { $permissions = array_keys($this->container->get('user.permissions')->getPermissions()); // Give the test user all permissions on the site. There should be no // permission that gives the user access to layout sections over REST. $this->account = $this->drupalCreateUser($permissions); } /** * {@inheritdoc} */ protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {} /** * {@inheritdoc} */ protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {} /** * {@inheritdoc} */ protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {} /** * {@inheritdoc} */ protected function getExpectedUnauthorizedAccessCacheability() {} /** * Gets the decoded contents. * * @param \Psr\Http\Message\ResponseInterface $response * The response. * * @return array * The decoded contents. */ protected function getDecodedContents(ResponseInterface $response) { return $this->serializer->decode((string) $response->getBody(), static::$format); } } Loading
core/modules/layout_builder/src/Field/LayoutSectionItemList.php +10 −0 Changes for core/modules/layout_builder/src/Field/LayoutSectionItemList.php: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,8 +2,10 @@ namespace Drupal\layout_builder\Field; use Drupal\Core\Access\AccessResult; use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Session\AccountInterface; use Drupal\layout_builder\Section; use Drupal\layout_builder\SectionListInterface; use Drupal\layout_builder\SectionStorage\SectionStorageTrait; Loading Loading @@ -74,4 +76,12 @@ public function equals(FieldItemListInterface $list_to_compare) { return $convert($this) === $convert($list_to_compare); } /** * {@inheritdoc} */ public function defaultAccess($operation = 'view', AccountInterface $account = NULL) { // @todo Allow access in https://www.drupal.org/node/2942975. return AccessResult::forbidden(); } }
core/modules/layout_builder/src/LayoutBuilderServiceProvider.php +10 −0 Changes for core/modules/layout_builder/src/LayoutBuilderServiceProvider.php: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -5,6 +5,8 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\layout_builder\EventSubscriber\SetInlineBlockDependency; use Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; Loading Loading @@ -35,6 +37,14 @@ public function register(ContainerBuilder $container) { $definition->addTag('event_subscriber'); $container->setDefinition('layout_builder.get_block_dependency_subscriber', $definition); } if (isset($modules['serialization'])) { $definition = (new ChildDefinition('serializer.normalizer.config_entity')) ->setClass(LayoutEntityDisplayNormalizer::class) // Ensure that this normalizer takes precedence for Layout Builder data // over the generic serializer.normalizer.config_entity. ->addTag('normalizer', ['priority' => 5]); $container->setDefinition('layout_builder.normalizer.layout_entity_display', $definition); } } }
core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php 0 → 100644 +33 −0 Changes for core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php: 33 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\layout_builder\Normalizer; use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; use Drupal\serialization\Normalizer\ConfigEntityNormalizer; /** * Normalizes/denormalizes LayoutEntityDisplay objects into an array structure. * * @internal * All tagged services are internal. */ class LayoutEntityDisplayNormalizer extends ConfigEntityNormalizer { /** * {@inheritdoc} */ protected $supportedInterfaceOrClass = LayoutEntityDisplayInterface::class; /** * {@inheritdoc} */ protected static function getDataWithoutInternals(array $data) { $data = parent::getDataWithoutInternals($data); // Do not expose the actual layout sections in normalization. // @todo Determine what to expose here in // https://www.drupal.org/node/2942975. unset($data['third_party_settings']['layout_builder']['sections']); return $data; } }
core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySectionsTest.php 0 → 100644 +61 −0 Changes for core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySectionsTest.php: 61 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional\Rest; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Url; /** * Tests that default layout sections are not exposed via the REST API. * * @group layout_builder * @group rest */ class EntityDisplaySectionsTest extends LayoutRestTestBase { /** * {@inheritdoc} */ protected static $resourceConfigId = 'entity.entity_view_display'; /** * Tests the normalization does not contain layout sections. */ public function testLayoutEntityDisplay() { $display_id = 'node.bundle_with_section_field.default'; $display = EntityViewDisplay::load($display_id); // Assert the display has 1 section. $this->assertCount(1, $display->getThirdPartySetting('layout_builder', 'sections')); $response = $this->request( 'GET', Url::fromRoute( 'rest.entity.entity_view_display.GET', ['entity_view_display' => 'node.bundle_with_section_field.default']) ); $this->assertResourceResponse( 200, FALSE, $response, [ 'config:core.entity_view_display.node.bundle_with_section_field.default', 'config:rest.resource.entity.entity_view_display', 'config:rest.settings', 'http_response', ], [ 'user.permissions', ], FALSE, 'MISS' ); $response_data = $this->getDecodedContents($response); $this->assertSame($display_id, $response_data['id']); // Ensure the sections are not present in the serialized data, but other // Layout Builder data is. $this->assertArrayHasKey('layout_builder', $response_data['third_party_settings']); $this->assertArrayNotHasKey('sections', $response_data['third_party_settings']['layout_builder']); $this->assertEquals(['enabled' => TRUE, 'allow_custom' => TRUE], $response_data['third_party_settings']['layout_builder']); } }
core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php 0 → 100644 +154 −0 Changes for core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php: 154 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\layout_builder\Functional\Rest; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Url; use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait; use Drupal\Tests\rest\Functional\ResourceTestBase; use GuzzleHttp\RequestOptions; use Psr\Http\Message\ResponseInterface; /** * Base class for Layout Builder REST tests. */ abstract class LayoutRestTestBase extends ResourceTestBase { use BasicAuthResourceTestTrait; /** * {@inheritdoc} */ public static $modules = [ 'node', 'layout_builder', 'serialization', 'basic_auth', ]; /** * A test node. * * @var \Drupal\node\NodeInterface */ protected $node; /** * The node storage. * * @var \Drupal\node\NodeStorageInterface */ protected $nodeStorage; /** * {@inheritdoc} */ public function setUp() { parent::setUp(); $assert_session = $this->assertSession(); // @todo The Layout Builder UI relies on local tasks; fix in // https://www.drupal.org/project/drupal/issues/2917777. $this->drupalPlaceBlock('local_tasks_block'); $this->createContentType(['type' => 'bundle_with_section_field']); $this->drupalLogin($this->drupalCreateUser([ 'configure any layout', 'administer node display', 'administer display modes', 'bypass node access', 'create bundle_with_section_field content', 'edit any bundle_with_section_field content', ])); $page = $this->getSession()->getPage(); $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field/display'; // Enable Layout Builder for the default view modes, and overrides. $this->drupalGet("$field_ui_prefix/default"); $page->checkField('layout[enabled]'); $page->pressButton('Save'); $page->checkField('layout[allow_custom]'); $page->pressButton('Save'); // Create a node. $this->node = $this->createNode([ 'type' => 'bundle_with_section_field', 'title' => 'A node at rest will stay at rest.', ]); $this->drupalGet('node/' . $this->node->id() . '/layout'); $page->clickLink('Layout'); $page->clickLink('Add Block'); $page->clickLink('Powered by Drupal'); $page->fillField('settings[label]', 'This is an override'); $page->checkField('settings[label_display]'); $page->pressButton('Add Block'); $page->clickLink('Save Layout'); $assert_session->pageTextContains('This is an override'); $this->nodeStorage = $this->container->get('entity_type.manager')->getStorage('node'); $this->node = $this->nodeStorage->load($this->node->id()); $this->drupalLogout(); $this->setUpAuthorization('ALL'); $this->provisionResource([static::$format], ['basic_auth']); } /** * {@inheritdoc} */ protected function request($method, Url $url, array $request_options = []) { $request_options[RequestOptions::HEADERS] = [ 'Content-Type' => static::$mimeType, ]; $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions($method)); $request_options[RequestOptions::QUERY] = ['_format' => static::$format]; return parent::request($method, $url, $request_options); } /** * {@inheritdoc} */ protected function setUpAuthorization($method) { $permissions = array_keys($this->container->get('user.permissions')->getPermissions()); // Give the test user all permissions on the site. There should be no // permission that gives the user access to layout sections over REST. $this->account = $this->drupalCreateUser($permissions); } /** * {@inheritdoc} */ protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {} /** * {@inheritdoc} */ protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {} /** * {@inheritdoc} */ protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {} /** * {@inheritdoc} */ protected function getExpectedUnauthorizedAccessCacheability() {} /** * Gets the decoded contents. * * @param \Psr\Http\Message\ResponseInterface $response * The response. * * @return array * The decoded contents. */ protected function getDecodedContents(ResponseInterface $response) { return $this->serializer->decode((string) $response->getBody(), static::$format); } }