class BlockComponentRenderArrayTest

Same name in other branches
  1. 9 core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php \Drupal\Tests\layout_builder\Unit\BlockComponentRenderArrayTest
  2. 8.9.x core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php \Drupal\Tests\layout_builder\Unit\BlockComponentRenderArrayTest
  3. 10 core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php \Drupal\Tests\layout_builder\Unit\BlockComponentRenderArrayTest

@coversDefaultClass \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray @group layout_builder

Hierarchy

Expanded class hierarchy of BlockComponentRenderArrayTest

File

core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php, line 31

Namespace

Drupal\Tests\layout_builder\Unit
View source
class BlockComponentRenderArrayTest extends UnitTestCase {
    
    /**
     * The current user.
     *
     * @var \Drupal\Core\Session\AccountInterface
     */
    protected $account;
    
    /**
     * The block plugin manager.
     *
     * @var \Drupal\Core\Block\BlockManagerInterface
     */
    protected $blockManager;
    
    /**
     * Data provider for test functions that should test block types.
     */
    public static function providerBlockTypes() {
        return [
            [
                TRUE,
            ],
            [
                FALSE,
            ],
        ];
    }
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        parent::setUp();
        $this->blockManager = $this->prophesize(BlockManagerInterface::class);
        $this->account = $this->prophesize(AccountInterface::class);
        $container = new ContainerBuilder();
        $container->set('plugin.manager.block', $this->blockManager
            ->reveal());
        $container->set('context.handler', $this->prophesize(ContextHandlerInterface::class));
        \Drupal::setContainer($container);
    }
    
    /**
     * @covers ::onBuildRender
     *
     * @dataProvider providerBlockTypes
     */
    public function testOnBuildRender($refinable_dependent_access) : void {
        $contexts = [];
        if ($refinable_dependent_access) {
            $block = $this->prophesize(TestBlockPluginWithRefinableDependentAccessInterface::class)
                ->willImplement(PreviewFallbackInterface::class);
            $layout_entity = $this->prophesize(EntityInterface::class);
            $layout_entity = $layout_entity->reveal();
            $context = $this->prophesize(ContextInterface::class);
            $context->getContextValue()
                ->willReturn($layout_entity);
            $contexts['layout_builder.entity'] = $context->reveal();
            $block->setAccessDependency($layout_entity)
                ->shouldBeCalled();
        }
        else {
            $block = $this->prophesize(BlockPluginInterface::class)
                ->willImplement(PreviewFallbackInterface::class);
        }
        $access_result = AccessResult::allowed();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $placeholder_label = 'Placeholder Label';
        $block->getPreviewFallbackString()
            ->willReturn($placeholder_label);
        $block_content = [
            '#markup' => 'The block content.',
            '#cache' => [
                'tags' => [
                    'build-tag',
                ],
            ],
        ];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $in_preview = FALSE;
        $event = new SectionComponentBuildRenderArrayEvent($component, $contexts, $in_preview);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [
            '#theme' => 'block',
            '#weight' => 0,
            '#configuration' => [],
            '#plugin_id' => 'block_plugin_id',
            '#base_plugin_id' => 'block_plugin_id',
            '#derivative_plugin_id' => NULL,
            'content' => $block_content,
            '#in_preview' => FALSE,
        ];
        $expected_build_with_expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'build-tag',
                    'test',
                ],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEqualsCanonicalizing($expected_build_with_expected_cache['#cache'], $result['#cache']);
    }
    
    /**
     * @covers ::onBuildRender
     *
     * @dataProvider providerBlockTypes
     */
    public function testOnBuildRenderWithoutPreviewFallbackString($refinable_dependent_access) : void {
        $contexts = [];
        if ($refinable_dependent_access) {
            $block = $this->prophesize(TestBlockPluginWithRefinableDependentAccessInterface::class);
            $layout_entity = $this->prophesize(EntityInterface::class);
            $layout_entity = $layout_entity->reveal();
            $context = $this->prophesize(ContextInterface::class);
            $context->getContextValue()
                ->willReturn($layout_entity);
            $contexts['layout_builder.entity'] = $context->reveal();
            $block->setAccessDependency($layout_entity)
                ->shouldBeCalled();
        }
        else {
            $block = $this->prophesize(BlockPluginInterface::class);
        }
        $access_result = AccessResult::allowed();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $placeholder_label = 'Placeholder Label';
        $block->label()
            ->willReturn($placeholder_label);
        $block_content = [
            '#markup' => 'The block content.',
        ];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $in_preview = FALSE;
        $event = new SectionComponentBuildRenderArrayEvent($component, $contexts, $in_preview);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $translation = $this->prophesize(TranslationInterface::class);
        $translation->translateString(Argument::type(TranslatableMarkup::class))
            ->willReturn($placeholder_label);
        $subscriber->setStringTranslation($translation->reveal());
        $expected_build = [
            '#theme' => 'block',
            '#weight' => 0,
            '#configuration' => [],
            '#plugin_id' => 'block_plugin_id',
            '#base_plugin_id' => 'block_plugin_id',
            '#derivative_plugin_id' => NULL,
            'content' => $block_content,
            '#in_preview' => FALSE,
        ];
        $expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'test',
                ],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEquals($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     *
     * @dataProvider providerBlockTypes
     */
    public function testOnBuildRenderDenied($refinable_dependent_access) : void {
        $contexts = [];
        if ($refinable_dependent_access) {
            $block = $this->prophesize(TestBlockPluginWithRefinableDependentAccessInterface::class);
            $layout_entity = $this->prophesize(EntityInterface::class);
            $layout_entity = $layout_entity->reveal();
            $context = $this->prophesize(ContextInterface::class);
            $context->getContextValue()
                ->willReturn($layout_entity);
            $contexts['layout_builder.entity'] = $context->reveal();
            $block->setAccessDependency($layout_entity)
                ->shouldBeCalled();
        }
        else {
            $block = $this->prophesize(BlockPluginInterface::class);
        }
        $access_result = AccessResult::forbidden();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->shouldNotBeCalled();
        $block->getCacheTags()
            ->shouldNotBeCalled();
        $block->getCacheMaxAge()
            ->shouldNotBeCalled();
        $block->getConfiguration()
            ->shouldNotBeCalled();
        $block->getPluginId()
            ->shouldNotBeCalled();
        $block->getBaseId()
            ->shouldNotBeCalled();
        $block->getDerivativeId()
            ->shouldNotBeCalled();
        $block_content = [
            '#markup' => 'The block content.',
        ];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $in_preview = FALSE;
        $event = new SectionComponentBuildRenderArrayEvent($component, $contexts, $in_preview);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [];
        $expected_cache = [
            '#cache' => [
                'contexts' => [],
                'tags' => [],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEquals($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     *
     * @dataProvider providerBlockTypes
     */
    public function testOnBuildRenderInPreview($refinable_dependent_access) : void {
        $contexts = [];
        if ($refinable_dependent_access) {
            $block = $this->prophesize(TestBlockPluginWithRefinableDependentAccessInterface::class)
                ->willImplement(PreviewFallbackInterface::class);
            $block->setAccessDependency(new LayoutPreviewAccessAllowed())
                ->shouldBeCalled();
            $layout_entity = $this->prophesize(EntityInterface::class);
            $layout_entity = $layout_entity->reveal();
            $layout_entity->in_preview = TRUE;
            $context = $this->prophesize(ContextInterface::class);
            $context->getContextValue()
                ->willReturn($layout_entity);
            $contexts['layout_builder.entity'] = $context->reveal();
        }
        else {
            $block = $this->prophesize(BlockPluginInterface::class)
                ->willImplement(PreviewFallbackInterface::class);
        }
        $block->access($this->account
            ->reveal(), TRUE)
            ->shouldNotBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $placeholder_label = 'Placeholder Label';
        $block->getPreviewFallbackString()
            ->willReturn($placeholder_label);
        $block_content = [
            '#markup' => 'The block content.',
        ];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $in_preview = TRUE;
        $event = new SectionComponentBuildRenderArrayEvent($component, $contexts, $in_preview);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [
            '#theme' => 'block',
            '#weight' => 0,
            '#configuration' => [],
            '#plugin_id' => 'block_plugin_id',
            '#base_plugin_id' => 'block_plugin_id',
            '#derivative_plugin_id' => NULL,
            'content' => $block_content,
            '#attributes' => [
                'data-layout-content-preview-placeholder-label' => $placeholder_label,
            ],
            '#in_preview' => TRUE,
        ];
        $expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'test',
                ],
                'max-age' => 0,
            ],
            '#in_preview' => TRUE,
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEquals($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     */
    public function testOnBuildRenderInPreviewEmptyBuild() : void {
        $block = $this->prophesize(BlockPluginInterface::class)
            ->willImplement(PreviewFallbackInterface::class);
        $block->access($this->account
            ->reveal(), TRUE)
            ->shouldNotBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $block->getPluginDefinition()
            ->willReturn([
            'admin_label' => 'admin',
        ]);
        $placeholder_string = 'The placeholder string';
        $block->getPreviewFallbackString()
            ->willReturn($placeholder_string);
        $block_content = [];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $event = new SectionComponentBuildRenderArrayEvent($component, [], TRUE);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $translation = $this->prophesize(TranslationInterface::class);
        $translation->translateString(Argument::type(TranslatableMarkup::class))
            ->willReturn($placeholder_string);
        $subscriber->setStringTranslation($translation->reveal());
        $expected_build = [
            '#theme' => 'block',
            '#weight' => 0,
            '#configuration' => [],
            '#plugin_id' => 'block_plugin_id',
            '#base_plugin_id' => 'block_plugin_id',
            '#derivative_plugin_id' => NULL,
            'content' => $block_content,
            '#attributes' => [
                'data-layout-content-preview-placeholder-label' => $placeholder_string,
            ],
            '#in_preview' => TRUE,
        ];
        $expected_build['content']['#markup'] = $placeholder_string;
        $expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'test',
                ],
                'max-age' => 0,
            ],
            '#in_preview' => TRUE,
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEquals($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     */
    public function testOnBuildRenderEmptyBuild() : void {
        $block = $this->prophesize(BlockPluginInterface::class);
        $access_result = AccessResult::allowed();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $block->build()
            ->willReturn([
            '#cache' => [
                'tags' => [
                    'build-tag',
                ],
            ],
        ]);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $event = new SectionComponentBuildRenderArrayEvent($component, [], FALSE);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [];
        $expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'build-tag',
                    'test',
                ],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEqualsCanonicalizing($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     */
    public function testOnBuildRenderEmptyBuildWithCacheTags() : void {
        $block = $this->prophesize(BlockPluginInterface::class);
        $access_result = AccessResult::allowed();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->getConfiguration()
            ->willReturn([]);
        $block->getPluginId()
            ->willReturn('block_plugin_id');
        $block->getBaseId()
            ->willReturn('block_plugin_id');
        $block->getDerivativeId()
            ->willReturn(NULL);
        $block_content = [
            '#cache' => [
                'tags' => [
                    'empty_build_cache_test',
                ],
            ],
        ];
        $block->build()
            ->willReturn($block_content);
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $event = new SectionComponentBuildRenderArrayEvent($component, [], FALSE);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [];
        $expected_cache = $expected_build + [
            '#cache' => [
                'contexts' => [],
                'tags' => [
                    'empty_build_cache_test',
                    'test',
                ],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEqualsCanonicalizing($expected_cache, $result);
    }
    
    /**
     * @covers ::onBuildRender
     */
    public function testOnBuildRenderNullBuild() : void {
        $block = $this->prophesize(BlockPluginInterface::class);
        $access_result = AccessResult::allowed();
        $block->access($this->account
            ->reveal(), TRUE)
            ->willReturn($access_result)
            ->shouldBeCalled();
        $block->getCacheContexts()
            ->willReturn([]);
        $block->getCacheTags()
            ->willReturn([
            'test',
        ]);
        $block->getCacheMaxAge()
            ->willReturn(Cache::PERMANENT);
        $block->build()
            ->willReturn(NULL);
        $this->expectException(\UnexpectedValueException::class);
        $this->expectExceptionMessage(sprintf('The block "%s" did not return an array', get_class($block->reveal())));
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn($block->reveal());
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $event = new SectionComponentBuildRenderArrayEvent($component, [], FALSE);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $subscriber->onBuildRender($event);
    }
    
    /**
     * @covers ::onBuildRender
     */
    public function testOnBuildRenderNoBlock() : void {
        $this->blockManager
            ->createInstance('some_block_id', [
            'id' => 'some_block_id',
        ])
            ->willReturn(NULL);
        $component = new SectionComponent('some-uuid', 'some-region', [
            'id' => 'some_block_id',
        ]);
        $contexts = [];
        $in_preview = FALSE;
        $event = new SectionComponentBuildRenderArrayEvent($component, $contexts, $in_preview);
        $subscriber = new BlockComponentRenderArray($this->account
            ->reveal());
        $expected_build = [];
        $expected_cache = [
            '#cache' => [
                'contexts' => [],
                'tags' => [],
                'max-age' => -1,
            ],
        ];
        $subscriber->onBuildRender($event);
        $result = $event->getBuild();
        $this->assertEquals($expected_build, $result);
        $event->getCacheableMetadata()
            ->applyTo($result);
        $this->assertEquals($expected_cache, $result);
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
BlockComponentRenderArrayTest::$account protected property The current user.
BlockComponentRenderArrayTest::$blockManager protected property The block plugin manager.
BlockComponentRenderArrayTest::providerBlockTypes public static function Data provider for test functions that should test block types.
BlockComponentRenderArrayTest::setUp protected function Overrides UnitTestCase::setUp
BlockComponentRenderArrayTest::testOnBuildRender public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderDenied public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderEmptyBuild public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderEmptyBuildWithCacheTags public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderInPreview public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderInPreviewEmptyBuild public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderNoBlock public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderNullBuild public function @covers ::onBuildRender
BlockComponentRenderArrayTest::testOnBuildRenderWithoutPreviewFallbackString public function @covers ::onBuildRender
ExpectDeprecationTrait::expectDeprecation public function Adds an expected deprecation.
ExpectDeprecationTrait::setUpErrorHandler public function Sets up the test error handler.
ExpectDeprecationTrait::tearDownErrorHandler public function Tears down the test error handler.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
UnitTestCase::$root protected property The app root.
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::setDebugDumpHandler public static function Registers the dumper CLI handler when the DebugDump extension is enabled.

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