OverridesSectionStorageTest.php

Same filename in this branch
  1. 11.x core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
Same filename in other branches
  1. 9 core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
  2. 9 core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
  3. 8.9.x core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
  4. 8.9.x core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
  5. 10 core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
  6. 10 core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php

Namespace

Drupal\Tests\layout_builder\Unit

File

core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\layout_builder\Unit;

use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

/**
 * @coversDefaultClass \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
 *
 * @group layout_builder
 * @group #slow
 */
class OverridesSectionStorageTest extends UnitTestCase {
    
    /**
     * The plugin.
     *
     * @var \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
     */
    protected $plugin;
    
    /**
     * The entity type manager.
     *
     * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     */
    protected $entityTypeManager;
    
    /**
     * The entity field manager.
     *
     * @var \Drupal\Core\Entity\EntityFieldManagerInterface
     */
    protected $entityFieldManager;
    
    /**
     * The entity repository.
     *
     * @var \Drupal\Core\Entity\EntityRepositoryInterface
     */
    protected $entityRepository;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        parent::setUp();
        $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
        $this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
        $section_storage_manager = $this->prophesize(SectionStorageManagerInterface::class);
        $this->entityRepository = $this->prophesize(EntityRepositoryInterface::class);
        $account = $this->prophesize(AccountInterface::class);
        $definition = new SectionStorageDefinition([
            'id' => 'overrides',
            'class' => OverridesSectionStorage::class,
        ]);
        $this->plugin = new OverridesSectionStorage([], 'overrides', $definition, $this->entityTypeManager
            ->reveal(), $this->entityFieldManager
            ->reveal(), $section_storage_manager->reveal(), $this->entityRepository
            ->reveal(), $account->reveal());
    }
    
    /**
     * @covers ::extractEntityFromRoute
     *
     * @dataProvider providerTestExtractEntityFromRoute
     *
     * @param bool $success
     *   Whether a successful result is expected.
     * @param string|null $expected_entity_type_id
     *   The expected entity type ID.
     * @param string $value
     *   The value to pass to ::extractEntityFromRoute().
     * @param array $defaults
     *   The defaults to pass to ::extractEntityFromRoute().
     */
    public function testExtractEntityFromRoute($success, $expected_entity_type_id, $value, array $defaults) : void {
        if ($expected_entity_type_id) {
            $entity_without_layout = $this->prophesize(FieldableEntityInterface::class);
            $entity_without_layout->hasField(OverridesSectionStorage::FIELD_NAME)
                ->willReturn(FALSE);
            $this->entityRepository
                ->getActive($expected_entity_type_id, 'entity_without_layout')
                ->willReturn($entity_without_layout->reveal());
            $entity_with_layout = $this->prophesize(FieldableEntityInterface::class);
            $entity_with_layout->hasField(OverridesSectionStorage::FIELD_NAME)
                ->willReturn(TRUE);
            $this->entityRepository
                ->getActive($expected_entity_type_id, 'entity_with_layout')
                ->willReturn($entity_with_layout->reveal());
            $entity_type = new EntityType([
                'id' => $expected_entity_type_id,
            ]);
            $this->entityTypeManager
                ->getDefinition($expected_entity_type_id)
                ->willReturn($entity_type);
        }
        else {
            $this->entityRepository
                ->getActive(Argument::any())
                ->shouldNotBeCalled();
        }
        $method = new \ReflectionMethod($this->plugin, 'extractEntityFromRoute');
        $result = $method->invoke($this->plugin, $value, $defaults);
        if ($success) {
            $this->assertInstanceOf(FieldableEntityInterface::class, $result);
        }
        else {
            $this->assertNull($result);
        }
    }
    
    /**
     * Provides data for ::testExtractEntityFromRoute().
     */
    public static function providerTestExtractEntityFromRoute() {
        // Data provider values are:
        // - whether a successful result is expected
        // - the expected entity ID
        // - the value to pass to ::extractEntityFromRoute()
        // - the defaults to pass to ::extractEntityFromRoute().
        $data = [];
        $data['with value, with layout'] = [
            TRUE,
            'my_entity_type',
            'my_entity_type.entity_with_layout',
            [],
        ];
        $data['with value, without layout'] = [
            TRUE,
            'my_entity_type',
            'my_entity_type.entity_without_layout',
            [],
        ];
        $data['empty value, populated defaults'] = [
            TRUE,
            'my_entity_type',
            '',
            [
                'entity_type_id' => 'my_entity_type',
                'my_entity_type' => 'entity_with_layout',
            ],
        ];
        $data['empty value, empty defaults'] = [
            FALSE,
            NULL,
            '',
            [],
        ];
        return $data;
    }
    
    /**
     * @covers ::buildRoutes
     * @covers ::hasIntegerId
     * @covers ::getEntityTypes
     * @covers \Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait::buildLayoutRoutes
     */
    public function testBuildRoutes() : void {
        $entity_types = [];
        $not_fieldable = $this->prophesize(EntityTypeInterface::class);
        $not_fieldable->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(FALSE);
        $entity_types['not_fieldable'] = $not_fieldable->reveal();
        $no_layout_builder_form = $this->prophesize(EntityTypeInterface::class);
        $no_layout_builder_form->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $no_layout_builder_form->hasHandlerClass('form', 'layout_builder')
            ->willReturn(FALSE);
        $entity_types['no_layout_builder_form'] = $no_layout_builder_form->reveal();
        $this->entityFieldManager
            ->getFieldStorageDefinitions('no_layout_builder_form')
            ->shouldNotBeCalled();
        $no_view_builder = $this->prophesize(EntityTypeInterface::class);
        $no_view_builder->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $no_view_builder->hasViewBuilderClass()
            ->willReturn(FALSE);
        $no_view_builder->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $entity_types['no_view_builder'] = $no_view_builder->reveal();
        $no_canonical_link = $this->prophesize(EntityTypeInterface::class);
        $no_canonical_link->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $no_canonical_link->hasViewBuilderClass()
            ->willReturn(TRUE);
        $no_canonical_link->hasLinkTemplate('canonical')
            ->willReturn(FALSE);
        $no_canonical_link->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $entity_types['no_canonical_link'] = $no_canonical_link->reveal();
        $this->entityFieldManager
            ->getFieldStorageDefinitions('no_canonical_link')
            ->shouldNotBeCalled();
        $canonical_link_no_route = $this->prophesize(EntityTypeInterface::class);
        $canonical_link_no_route->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $canonical_link_no_route->hasViewBuilderClass()
            ->willReturn(TRUE);
        $canonical_link_no_route->hasLinkTemplate('canonical')
            ->willReturn(TRUE);
        $canonical_link_no_route->getLinkTemplate('canonical')
            ->willReturn('/entity/{entity}');
        $canonical_link_no_route->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $entity_types['canonical_link_no_route'] = $canonical_link_no_route->reveal();
        $this->entityFieldManager
            ->getFieldStorageDefinitions('canonical_link_no_route')
            ->shouldNotBeCalled();
        $from_canonical = $this->prophesize(EntityTypeInterface::class);
        $from_canonical->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $from_canonical->hasViewBuilderClass()
            ->willReturn(TRUE);
        $from_canonical->hasLinkTemplate('canonical')
            ->willReturn(TRUE);
        $from_canonical->getLinkTemplate('canonical')
            ->willReturn('/entity/{entity}');
        $from_canonical->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $entity_types['from_canonical'] = $from_canonical->reveal();
        $with_string_id = $this->prophesize(EntityTypeInterface::class);
        $with_string_id->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $with_string_id->hasViewBuilderClass()
            ->willReturn(TRUE);
        $with_string_id->hasLinkTemplate('canonical')
            ->willReturn(TRUE);
        $with_string_id->getLinkTemplate('canonical')
            ->willReturn('/entity/{entity}');
        $with_string_id->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $with_string_id->id()
            ->willReturn('with_string_id');
        $with_string_id->getKey('id')
            ->willReturn('id');
        $entity_types['with_string_id'] = $with_string_id->reveal();
        $string_id = $this->prophesize(FieldStorageDefinitionInterface::class);
        $string_id->getType()
            ->willReturn('string');
        $this->entityFieldManager
            ->getFieldStorageDefinitions('with_string_id')
            ->willReturn([
            'id' => $string_id->reveal(),
        ]);
        $with_integer_id = $this->prophesize(EntityTypeInterface::class);
        $with_integer_id->entityClassImplements(FieldableEntityInterface::class)
            ->willReturn(TRUE);
        $with_integer_id->hasViewBuilderClass()
            ->willReturn(TRUE);
        $with_integer_id->hasLinkTemplate('canonical')
            ->willReturn(TRUE);
        $with_integer_id->getLinkTemplate('canonical')
            ->willReturn('/entity/{entity}');
        $with_integer_id->hasHandlerClass('form', 'layout_builder')
            ->willReturn(TRUE);
        $with_integer_id->id()
            ->willReturn('with_integer_id');
        $with_integer_id->getKey('id')
            ->willReturn('id');
        $entity_types['with_integer_id'] = $with_integer_id->reveal();
        $integer_id = $this->prophesize(FieldStorageDefinitionInterface::class);
        $integer_id->getType()
            ->willReturn('integer');
        $this->entityFieldManager
            ->getFieldStorageDefinitions('with_integer_id')
            ->willReturn([
            'id' => $integer_id->reveal(),
        ]);
        $this->entityTypeManager
            ->getDefinitions()
            ->willReturn($entity_types);
        $expected = [
            'entity.from_canonical.canonical' => new Route('/entity/{entity}', [], [
                'custom requirement' => 'from_canonical_route',
            ]),
            'entity.with_string_id.canonical' => new Route('/entity/{entity}'),
            'entity.with_integer_id.canonical' => new Route('/entity/{entity}', [], [
                'with_integer_id' => '\\d+',
            ]),
            'layout_builder.overrides.from_canonical.view' => new Route('/entity/{entity}/layout', [
                'entity_type_id' => 'from_canonical',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_entity_form' => 'from_canonical.layout_builder',
                '_title_callback' => '\\Drupal\\layout_builder\\Controller\\LayoutBuilderController::title',
            ], [
                '_layout_builder_access' => 'view',
                'custom requirement' => 'from_canonical_route',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'from_canonical' => [
                        'type' => 'entity:from_canonical',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.from_canonical.discard_changes' => new Route('/entity/{entity}/layout/discard-changes', [
                'entity_type_id' => 'from_canonical',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\DiscardLayoutChangesForm',
            ], [
                '_layout_builder_access' => 'view',
                'custom requirement' => 'from_canonical_route',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'from_canonical' => [
                        'type' => 'entity:from_canonical',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.from_canonical.revert' => new Route('/entity/{entity}/layout/revert', [
                'entity_type_id' => 'from_canonical',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\RevertOverridesForm',
            ], [
                '_layout_builder_access' => 'view',
                'custom requirement' => 'from_canonical_route',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'from_canonical' => [
                        'type' => 'entity:from_canonical',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_string_id.view' => new Route('/entity/{entity}/layout', [
                'entity_type_id' => 'with_string_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_title_callback' => '\\Drupal\\layout_builder\\Controller\\LayoutBuilderController::title',
                '_entity_form' => 'with_string_id.layout_builder',
            ], [
                '_layout_builder_access' => 'view',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_string_id' => [
                        'type' => 'entity:with_string_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_string_id.discard_changes' => new Route('/entity/{entity}/layout/discard-changes', [
                'entity_type_id' => 'with_string_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\DiscardLayoutChangesForm',
            ], [
                '_layout_builder_access' => 'view',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_string_id' => [
                        'type' => 'entity:with_string_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_string_id.revert' => new Route('/entity/{entity}/layout/revert', [
                'entity_type_id' => 'with_string_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\RevertOverridesForm',
            ], [
                '_layout_builder_access' => 'view',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_string_id' => [
                        'type' => 'entity:with_string_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_integer_id.view' => new Route('/entity/{entity}/layout', [
                'entity_type_id' => 'with_integer_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_title_callback' => '\\Drupal\\layout_builder\\Controller\\LayoutBuilderController::title',
                '_entity_form' => 'with_integer_id.layout_builder',
            ], [
                '_layout_builder_access' => 'view',
                'with_integer_id' => '\\d+',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_integer_id' => [
                        'type' => 'entity:with_integer_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_integer_id.discard_changes' => new Route('/entity/{entity}/layout/discard-changes', [
                'entity_type_id' => 'with_integer_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\DiscardLayoutChangesForm',
            ], [
                '_layout_builder_access' => 'view',
                'with_integer_id' => '\\d+',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_integer_id' => [
                        'type' => 'entity:with_integer_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
            'layout_builder.overrides.with_integer_id.revert' => new Route('/entity/{entity}/layout/revert', [
                'entity_type_id' => 'with_integer_id',
                'section_storage_type' => 'overrides',
                'section_storage' => '',
                '_form' => '\\Drupal\\layout_builder\\Form\\RevertOverridesForm',
            ], [
                '_layout_builder_access' => 'view',
                'with_integer_id' => '\\d+',
            ], [
                'parameters' => [
                    'section_storage' => [
                        'layout_builder_tempstore' => TRUE,
                    ],
                    'with_integer_id' => [
                        'type' => 'entity:with_integer_id',
                    ],
                ],
                '_layout_builder' => TRUE,
                '_admin_route' => FALSE,
            ]),
        ];
        $collection = new RouteCollection();
        // Entity types that declare a link template for canonical must have a
        // canonical route present in the route collection.
        $collection->add('entity.from_canonical.canonical', $expected['entity.from_canonical.canonical']);
        $collection->add('entity.with_string_id.canonical', $expected['entity.with_string_id.canonical']);
        $collection->add('entity.with_integer_id.canonical', $expected['entity.with_integer_id.canonical']);
        $this->plugin
            ->buildRoutes($collection);
        $this->assertEquals($expected, $collection->all());
        $this->assertSame(array_keys($expected), array_keys($collection->all()));
    }

}

Classes

Title Deprecated Summary
OverridesSectionStorageTest @coversDefaultClass \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.