Skip to content
Snippets Groups Projects
Verified Commit 091483c1 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3420983 by sorlov, godotislate, alexpott, quietone, kim.pepper,...

Issue #3420983 by sorlov, godotislate, alexpott, quietone, kim.pepper, larowlan, mstrelan: Convert Layout plugin discovery to attributes
parent 74a6dce2
Branches
Tags
26 merge requests!11131[10.4.x-only-DO-NOT-MERGE]: Issue ##2842525 Ajax attached to Views exposed filter form does not trigger callbacks,!9470[10.3.x-only-DO-NOT-MERGE]: #3331771 Fix file_get_contents(): Passing null to parameter,!8540Issue #3457061: Bootstrap Modal dialog Not closing after 10.3.0 Update,!8528Issue #3456871 by Tim Bozeman: Support NULL services,!8373Issue #3427374 by danflanagan8, Vighneshh: taxonomy_tid ViewsArgumentDefault...,!3878Removed unused condition head title for views,!3818Issue #2140179: $entity->original gets stale between updates,!3742Issue #3328429: Create item list field formatter for displaying ordered and unordered lists,!3731Claro: role=button on status report items,!3651Issue #3347736: Create new SDC component for Olivero (header-search),!3531Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!3355Issue #3209129: Scrolling problems when adding a block via layout builder,!3154Fixes #2987987 - CSRF token validation broken on routes with optional parameters.,!3133core/modules/system/css/components/hidden.module.css,!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!2812Issue #3312049: [Followup] Fix Drupal.Commenting.FunctionComment.MissingReturnType returns for NULL,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2062Issue #3246454: Add weekly granularity to views date sort,!1105Issue #3025039: New non translatable field on translatable content throws error,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!877Issue #2708101: Default value for link text is not saved,!617Issue #3043725: Provide a Entity Handler for user cancelation,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493
Pipeline #163269 canceled
Pipeline: drupal

#163274

    Showing
    with 319 additions and 113 deletions
    <?php
    namespace Drupal\Core\Layout\Attribute;
    use Drupal\Component\Plugin\Attribute\Plugin;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\Layout\LayoutDefinition;
    /**
    * Defines a Layout attribute object.
    *
    * Layouts are used to define a list of regions and then output render arrays
    * in each of the regions, usually using a template.
    *
    * Plugin Namespace: Plugin\Layout
    *
    * @see \Drupal\Core\Layout\LayoutInterface
    * @see \Drupal\Core\Layout\LayoutDefault
    * @see \Drupal\Core\Layout\LayoutPluginManager
    * @see plugin_api
    */
    #[\Attribute(\Attribute::TARGET_CLASS)]
    class Layout extends Plugin {
    /**
    * Any additional properties and values.
    *
    * @see \Drupal\Core\Layout\LayoutDefinition::$additional
    *
    * @var array
    */
    public readonly array $additional;
    /**
    * Constructs a Layout attribute.
    *
    * @param string $id
    * The plugin ID.
    * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $label
    * (optional) The human-readable name. @todo Deprecate optional label in
    * https://www.drupal.org/project/drupal/issues/3392572.
    * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $category
    * (optional) The human-readable category. @todo Deprecate optional category
    * in https://www.drupal.org/project/drupal/issues/3392572.
    * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
    * (optional) The description for advanced layouts.
    * @param string|null $template
    * (optional) The template file to render the layout.
    * @param string $theme_hook
    * (optional) The template hook to render the layout.
    * @param string|null $path
    * (optional) Path (relative to the module or theme) to resources like icon or template.
    * @param string|null $library
    * (optional) The asset library.
    * @param string|null $icon
    * (optional) The path to the preview image (relative to the 'path' given).
    * @param string[][]|null $icon_map
    * (optional) The icon map.
    * @param array $regions
    * (optional) An associative array of regions in this layout.
    * @param string|null $default_region
    * (optional) The default region.
    * @param class-string $class
    * (optional) The layout plugin class.
    * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface[] $context_definitions
    * (optional) The context definition.
    * @param array $config_dependencies
    * (optional) The config dependencies.
    * @param class-string|null $deriver
    * (optional) The deriver class.
    * @param mixed $additional
    * (optional) Additional properties passed in that can be used by a deriver.
    */
    public function __construct(
    public readonly string $id,
    public readonly ?TranslatableMarkup $label = NULL,
    public readonly ?TranslatableMarkup $category = NULL,
    public readonly ?TranslatableMarkup $description = NULL,
    public readonly ?string $template = NULL,
    public readonly string $theme_hook = 'layout',
    public readonly ?string $path = NULL,
    public readonly ?string $library = NULL,
    public readonly ?string $icon = NULL,
    public readonly ?array $icon_map = NULL,
    public readonly array $regions = [],
    public readonly ?string $default_region = NULL,
    public string $class = LayoutDefault::class,
    public readonly array $context_definitions = [],
    public readonly array $config_dependencies = [],
    public readonly ?string $deriver = NULL,
    ...$additional,
    ) {
    // Layout definitions support arbitrary properties being passed in, which
    // are stored in the 'additional' property in LayoutDefinition. The variadic
    // 'additional' parameter here saves arbitrary parameters passed into the
    // 'additional' property in this attribute class. The 'additional' property
    // gets passed to the LayoutDefinition constructor in ::get().
    // @see \Drupal\Core\Layout\LayoutDefinition::$additional
    // @see \Drupal\Core\Layout\LayoutDefinition::get()
    $this->additional = $additional;
    }
    /**
    * {@inheritdoc}
    */
    public function get(): LayoutDefinition {
    return new LayoutDefinition(parent::get());
    }
    }
    ......@@ -132,7 +132,7 @@ class LayoutDefinition extends PluginDefinition implements PluginDefinitionInter
    * LayoutDefinition constructor.
    *
    * @param array $definition
    * An array of values from the annotation.
    * An array of values from the attribute.
    */
    public function __construct(array $definition) {
    // If there are context definitions in the plugin definition, they should
    ......
    ......@@ -2,16 +2,16 @@
    namespace Drupal\Core\Layout;
    use Drupal\Component\Annotation\Plugin\Discovery\AnnotationBridgeDecorator;
    use Drupal\Component\Plugin\Discovery\AttributeBridgeDecorator;
    use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
    use Drupal\Core\Cache\CacheBackendInterface;
    use Drupal\Core\Extension\ModuleHandlerInterface;
    use Drupal\Core\Extension\ThemeHandlerInterface;
    use Drupal\Core\Plugin\DefaultPluginManager;
    use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
    use Drupal\Core\Plugin\Discovery\AttributeDiscoveryWithAnnotations;
    use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
    use Drupal\Core\Plugin\Discovery\YamlDiscoveryDecorator;
    use Drupal\Core\Layout\Annotation\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Plugin\FilteredPluginManagerTrait;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    ......@@ -43,7 +43,7 @@ class LayoutPluginManager extends DefaultPluginManager implements LayoutPluginMa
    * The theme handler to invoke the alter hook with.
    */
    public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler) {
    parent::__construct('Plugin/Layout', $namespaces, $module_handler, LayoutInterface::class, Layout::class);
    parent::__construct('Plugin/Layout', $namespaces, $module_handler, LayoutInterface::class, Layout::class, 'Drupal\Core\Layout\Annotation\Layout');
    $this->themeHandler = $theme_handler;
    $type = $this->getType();
    ......@@ -70,13 +70,13 @@ protected function providerExists($provider) {
    */
    protected function getDiscovery() {
    if (!$this->discovery) {
    $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
    $discovery = new AttributeDiscoveryWithAnnotations($this->subdir, $this->namespaces, $this->pluginDefinitionAttributeName, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
    $discovery = new YamlDiscoveryDecorator($discovery, 'layouts', $this->moduleHandler->getModuleDirectories() + $this->themeHandler->getThemeDirectories());
    $discovery
    ->addTranslatableProperty('label')
    ->addTranslatableProperty('description')
    ->addTranslatableProperty('category');
    $discovery = new AnnotationBridgeDecorator($discovery, $this->pluginDefinitionAnnotationName);
    $discovery = new AttributeBridgeDecorator($discovery, $this->pluginDefinitionAttributeName);
    $discovery = new ContainerDerivativeDiscoveryDecorator($discovery);
    $this->discovery = $discovery;
    }
    ......
    ......@@ -2,26 +2,27 @@
    namespace Drupal\field_layout_test\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * Provides an annotated layout plugin for field_layout tests.
    *
    * @Layout(
    * id = "test_layout_content_and_footer",
    * label = @Translation("Test plugin: Content and Footer"),
    * category = @Translation("Layout test"),
    * description = @Translation("Test layout"),
    * regions = {
    * "content" = {
    * "label" = @Translation("Content Region")
    * },
    * "footer" = {
    * "label" = @Translation("Footer Region")
    * }
    * },
    * )
    * Provides a Layout plugin for field_layout tests.
    */
    #[Layout(
    id: 'test_layout_content_and_footer',
    label: new TranslatableMarkup('Test plugin: Content and Footer'),
    category: new TranslatableMarkup('Layout test'),
    description: new TranslatableMarkup('Test layout'),
    regions: [
    "content" => [
    "label" => new TranslatableMarkup("Content Region"),
    ],
    "footer" => [
    "label" => new TranslatableMarkup("Footer Region"),
    ],
    ],
    )]
    class TestLayoutContentFooter extends LayoutDefault {
    }
    ......@@ -2,31 +2,32 @@
    namespace Drupal\field_layout_test\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * Provides an annotated layout plugin for field_layout tests.
    *
    * @Layout(
    * id = "test_layout_main_and_footer",
    * label = @Translation("Test plugin: Main and Footer"),
    * category = @Translation("Layout test"),
    * description = @Translation("Test layout"),
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * },
    * "footer" = {
    * "label" = @Translation("Footer Region")
    * }
    * },
    * config_dependencies = {
    * "module" = {
    * "layout_discovery",
    * },
    * },
    * )
    * Provides an attributed layout plugin for field_layout tests.
    */
    #[Layout(
    id: 'test_layout_main_and_footer',
    label: new TranslatableMarkup('Test plugin: Main and Footer'),
    category: new TranslatableMarkup('Layout test'),
    description: new TranslatableMarkup('Test layout'),
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    "footer" => [
    "label" => new TranslatableMarkup("Footer Region"),
    ],
    ],
    config_dependencies: [
    "module" => [
    "layout_discovery",
    ],
    ],
    )]
    class TestLayoutMainFooter extends LayoutDefault {
    /**
    ......
    ......@@ -15,7 +15,7 @@
    *
    * By default, the Layout Builder access check requires the 'configure any
    * layout' permission. Individual section storage plugins may override this by
    * setting the 'handles_permission_check' annotation key to TRUE. Any section
    * setting the 'handles_permission_check' attribute key to TRUE. Any section
    * storage plugin that uses 'handles_permission_check' must provide its own
    * complete routing access checking to avoid any access bypasses.
    *
    ......
    ......@@ -2,7 +2,9 @@
    namespace Drupal\layout_builder\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * Provides a layout plugin that produces no output.
    ......@@ -13,11 +15,11 @@
    *
    * @internal
    * This layout plugin is intended for internal use by Layout Builder only.
    *
    * @Layout(
    * id = "layout_builder_blank",
    * )
    */
    #[Layout(
    id: 'layout_builder_blank',
    label: new TranslatableMarkup('Blank'),
    )]
    class BlankLayout extends LayoutDefault {
    /**
    ......
    ......@@ -2,19 +2,22 @@
    namespace Drupal\layout_builder_test\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * @Layout(
    * id = "layout_builder_test_plugin",
    * label = @Translation("Layout Builder Test Plugin"),
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * }
    * },
    * )
    * The Layout Builder Test Plugin.
    */
    #[Layout(
    id: 'layout_builder_test_plugin',
    label: new TranslatableMarkup('Layout Builder Test Plugin'),
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    ],
    )]
    class LayoutBuilderTestPlugin extends LayoutDefault {
    /**
    ......
    ......@@ -3,21 +3,22 @@
    namespace Drupal\layout_builder_test\Plugin\Layout;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * Layout plugin without a label configuration.
    *
    * @Layout(
    * id = "layout_without_label",
    * label = @Translation("Layout Without Label"),
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * }
    * },
    * )
    */
    #[Layout(
    id: 'layout_without_label',
    label: new TranslatableMarkup('Layout Without Label'),
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    ],
    )]
    class LayoutWithoutLabel extends LayoutDefault {
    /**
    ......
    ......@@ -2,22 +2,26 @@
    namespace Drupal\layout_builder_test\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\Plugin\Context\EntityContextDefinition;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * @Layout(
    * id = "layout_builder_test_context_aware",
    * label = @Translation("Layout Builder Test: Context Aware"),
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * }
    * },
    * context_definitions = {
    * "user" = @ContextDefinition("entity:user")
    * }
    * )
    * The TestContextAwareLayout Class.
    */
    #[Layout(
    id: 'layout_builder_test_context_aware',
    label: new TranslatableMarkup('Layout Builder Test: Context Aware'),
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    ],
    context_definitions: [
    "user" => new EntityContextDefinition("entity:user"),
    ],
    )]
    class TestContextAwareLayout extends LayoutDefault {
    /**
    ......
    ......@@ -3,23 +3,24 @@
    namespace Drupal\layout_test\Plugin\Layout;
    use Drupal\Component\Plugin\DependentPluginInterface;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * Provides a plugin that contains config dependencies.
    *
    * @Layout(
    * id = "layout_test_dependencies_plugin",
    * label = @Translation("Layout plugin (with dependencies)"),
    * category = @Translation("Layout test"),
    * description = @Translation("Test layout"),
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * }
    * }
    * )
    */
    #[Layout(
    id: 'layout_test_dependencies_plugin',
    label: new TranslatableMarkup('Layout plugin (with dependencies)'),
    category: new TranslatableMarkup('Layout test'),
    description: new TranslatableMarkup('Test layout'),
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    ],
    )]
    class LayoutTestDependenciesPlugin extends LayoutDefault implements DependentPluginInterface {
    /**
    ......
    ......@@ -3,25 +3,26 @@
    namespace Drupal\layout_test\Plugin\Layout;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\Plugin\PluginFormInterface;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * The plugin that handles the default layout template.
    *
    * @Layout(
    * id = "layout_test_plugin",
    * label = @Translation("Layout plugin (with settings)"),
    * category = @Translation("Layout test"),
    * description = @Translation("Test layout"),
    * template = "templates/layout-test-plugin",
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region")
    * }
    * }
    * )
    */
    #[Layout(
    id: 'layout_test_plugin',
    label: new TranslatableMarkup('Layout plugin (with settings)'),
    category: new TranslatableMarkup('Layout test'),
    description: new TranslatableMarkup('Test layout'),
    template: "templates/layout-test-plugin",
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region"),
    ],
    ],
    )]
    class LayoutTestPlugin extends LayoutDefault implements PluginFormInterface {
    /**
    ......
    ......@@ -4,6 +4,7 @@
    namespace Drupal\Tests\Core\Layout;
    use Composer\Autoload\ClassLoader;
    use Drupal\Component\Plugin\Derivative\DeriverBase;
    use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
    use Drupal\Core\Cache\CacheBackendInterface;
    ......@@ -20,6 +21,8 @@
    use org\bovigo\vfs\vfsStream;
    use Prophecy\Argument;
    // cspell:ignore lorem, ipsum, consectetur, adipiscing
    /**
    * @coversDefaultClass \Drupal\Core\Layout\LayoutPluginManager
    * @group Layout
    ......@@ -91,6 +94,9 @@ protected function setUp(): void {
    $this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
    $namespaces = new \ArrayObject(['Drupal\Core' => vfsStream::url('root/core/lib/Drupal/Core')]);
    $class_loader = new ClassLoader();
    $class_loader->addPsr4("Drupal\\Core\\", vfsStream::url("root/core/lib/Drupal/Core"));
    $class_loader->register(TRUE);
    $this->layoutPluginManager = new LayoutPluginManager($namespaces, $this->cacheBackend->reveal(), $this->moduleHandler->reveal(), $this->themeHandler->reveal());
    }
    ......@@ -103,6 +109,7 @@ public function testGetDefinitions() {
    'module_a_provided_layout',
    'theme_a_provided_layout',
    'plugin_provided_layout',
    'plugin_provided_by_annotation_layout',
    ];
    $layout_definitions = $this->layoutPluginManager->getDefinitions();
    ......@@ -172,6 +179,8 @@ public function testGetDefinition() {
    $this->assertEquals($expected_regions, $regions);
    $this->assertInstanceOf(TranslatableMarkup::class, $regions['top']['label']);
    $this->assertInstanceOf(TranslatableMarkup::class, $regions['bottom']['label']);
    // Check that arbitrary property value gets set correctly.
    $this->assertSame('ipsum', $layout_definition->get('lorem'));
    $core_path = '/core/lib/Drupal/Core';
    $layout_definition = $this->layoutPluginManager->getDefinition('plugin_provided_layout');
    ......@@ -198,6 +207,37 @@ public function testGetDefinition() {
    $regions = $layout_definition->getRegions();
    $this->assertEquals($expected_regions, $regions);
    $this->assertInstanceOf(TranslatableMarkup::class, $regions['main']['label']);
    // Check that arbitrary property value gets set correctly.
    $this->assertSame('adipiscing', $layout_definition->get('consectetur'));
    $layout_definition = $this->layoutPluginManager->getDefinition('plugin_provided_by_annotation_layout');
    $this->assertSame('plugin_provided_by_annotation_layout', $layout_definition->id());
    $this->assertEquals('Layout by annotation plugin', $layout_definition->getLabel());
    $this->assertEquals('Columns: 2', $layout_definition->getCategory());
    $this->assertEquals('Test layout provided by annotated plugin', $layout_definition->getDescription());
    $this->assertInstanceOf(TranslatableMarkup::class, $layout_definition->getLabel());
    $this->assertInstanceOf(TranslatableMarkup::class, $layout_definition->getCategory());
    $this->assertInstanceOf(TranslatableMarkup::class, $layout_definition->getDescription());
    $this->assertSame('plugin-provided-annotation-layout', $layout_definition->getTemplate());
    $this->assertSame($core_path, $layout_definition->getPath());
    $this->assertNull($layout_definition->getLibrary());
    $this->assertSame('plugin_provided_annotation_layout', $layout_definition->getThemeHook());
    $this->assertSame("$core_path/templates", $layout_definition->getTemplatePath());
    $this->assertSame('core', $layout_definition->getProvider());
    $this->assertSame('left', $layout_definition->getDefaultRegion());
    $this->assertSame('Drupal\Core\Plugin\Layout\TestAnnotationLayout', $layout_definition->getClass());
    $expected_regions = [
    'left' => [
    'label' => new TranslatableMarkup('Left Region', [], ['context' => 'layout_region']),
    ],
    'right' => [
    'label' => new TranslatableMarkup('Right Region', [], ['context' => 'layout_region']),
    ],
    ];
    $regions = $layout_definition->getRegions();
    $this->assertEquals($expected_regions, $regions);
    $this->assertInstanceOf(TranslatableMarkup::class, $regions['left']['label']);
    $this->assertInstanceOf(TranslatableMarkup::class, $regions['right']['label']);
    }
    /**
    ......@@ -243,6 +283,12 @@ public function testGetThemeImplementations() {
    'template' => 'plugin-provided-layout',
    'path' => "$core_path/templates",
    ],
    'plugin_provided_annotation_layout' => [
    'render element' => 'content',
    'base hook' => 'layout',
    'template' => 'plugin-provided-annotation-layout',
    'path' => "$core_path/templates",
    ],
    ];
    $theme_implementations = $this->layoutPluginManager->getThemeImplementations();
    $this->assertEquals($expected, $theme_implementations);
    ......@@ -264,10 +310,12 @@ public function testGetCategories() {
    * @covers ::getSortedDefinitions
    */
    public function testGetSortedDefinitions() {
    // Sorted by category first, then label.
    $expected = [
    'module_a_provided_layout',
    'plugin_provided_layout',
    'theme_a_provided_layout',
    'plugin_provided_by_annotation_layout',
    ];
    $layout_definitions = $this->layoutPluginManager->getSortedDefinitions();
    ......@@ -286,6 +334,7 @@ public function testGetGroupedDefinitions() {
    ],
    'Columns: 2' => [
    'theme_a_provided_layout',
    'plugin_provided_by_annotation_layout',
    ],
    ];
    ......@@ -315,7 +364,9 @@ protected function setUpFilesystem() {
    label: Top region
    bottom:
    label: Bottom region
    lorem: ipsum
    module_a_derived_layout:
    label: 'Invalid provider derived layout'
    deriver: \Drupal\Tests\Core\Layout\LayoutDeriver
    invalid_provider: true
    EOS;
    ......@@ -338,23 +389,52 @@ class: '\Drupal\Core\Layout\LayoutDefault'
    $plugin_provided_layout = <<<'EOS'
    <?php
    namespace Drupal\Core\Plugin\Layout;
    use Drupal\Core\Layout\Attribute\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    use Drupal\Core\StringTranslation\TranslatableMarkup;
    /**
    * The TestLayout Class.
    */
    #[Layout(
    id: 'plugin_provided_layout',
    label: new TranslatableMarkup('Layout plugin'),
    category: new TranslatableMarkup('Columns: 1'),
    description: new TranslatableMarkup('Test layout'),
    path: "core/lib/Drupal/Core",
    template: "templates/plugin-provided-layout",
    regions: [
    "main" => [
    "label" => new TranslatableMarkup("Main Region", [], ["context" => "layout_region"]),
    ],
    ],
    consectetur: 'adipiscing',
    )]
    class TestLayout extends LayoutDefault {}
    EOS;
    $plugin_provided_by_annotation_layout = <<<'EOS'
    <?php
    namespace Drupal\Core\Plugin\Layout;
    use Drupal\Core\Layout\LayoutDefault;
    /**
    * @Layout(
    * id = "plugin_provided_layout",
    * label = @Translation("Layout plugin"),
    * category = @Translation("Columns: 1"),
    * description = @Translation("Test layout"),
    * id = "plugin_provided_by_annotation_layout",
    * label = @Translation("Layout by annotation plugin"),
    * category = @Translation("Columns: 2"),
    * description = @Translation("Test layout provided by annotated plugin"),
    * path = "core/lib/Drupal/Core",
    * template = "templates/plugin-provided-layout",
    * template = "templates/plugin-provided-annotation-layout",
    * default_region = "left",
    * regions = {
    * "main" = {
    * "label" = @Translation("Main Region", context = "layout_region")
    * "left" = {
    * "label" = @Translation("Left Region", context = "layout_region")
    * },
    * "right" = {
    * "label" = @Translation("Right Region", context = "layout_region")
    * }
    * }
    * )
    */
    class TestLayout extends LayoutDefault {}
    class TestAnnotationLayout extends LayoutDefault {}
    EOS;
    vfsStream::setup('root');
    vfsStream::create([
    ......@@ -379,6 +459,7 @@ class TestLayout extends LayoutDefault {}
    'Plugin' => [
    'Layout' => [
    'TestLayout.php' => $plugin_provided_layout,
    'TestAnnotationLayout.php' => $plugin_provided_by_annotation_layout,
    ],
    ],
    ],
    ......
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please register or to comment