Issue #2949177 by tim.plunkett, samuel.mortenson, mark_fullmer, tedbow, EclipseGc, andypost: Introduce a service that returns filtered plugin definitions
parent
223216cb94
commit
e91d969537
|
@ -33,6 +33,8 @@ interface DiscoveryInterface {
|
|||
* @return mixed[]
|
||||
* An array of plugin definitions (empty array if no definitions were
|
||||
* found). Keys are plugin IDs.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\FilteredPluginManagerInterface::getFilteredDefinitions()
|
||||
*/
|
||||
public function getDefinitions();
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ use Drupal\Component\Plugin\FallbackPluginManagerInterface;
|
|||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\CategorizingPluginManagerTrait;
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Manages discovery and instantiation of block plugins.
|
||||
|
@ -21,7 +21,7 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
|
|||
use CategorizingPluginManagerTrait {
|
||||
getSortedDefinitions as traitGetSortedDefinitions;
|
||||
}
|
||||
use ContextAwarePluginManagerTrait;
|
||||
use FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Constructs a new \Drupal\Core\Block\BlockManager object.
|
||||
|
@ -37,10 +37,17 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
|
|||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/Block', $namespaces, $module_handler, 'Drupal\Core\Block\BlockPluginInterface', 'Drupal\Core\Block\Annotation\Block');
|
||||
|
||||
$this->alterInfo('block');
|
||||
$this->alterInfo($this->getType());
|
||||
$this->setCacheBackend($cache_backend, 'block_plugins');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType() {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -4,10 +4,11 @@ namespace Drupal\Core\Block;
|
|||
|
||||
use Drupal\Component\Plugin\CategorizingPluginManagerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for the discovery and instantiation of block plugins.
|
||||
*/
|
||||
interface BlockManagerInterface extends ContextAwarePluginManagerInterface, CategorizingPluginManagerInterface {
|
||||
interface BlockManagerInterface extends ContextAwarePluginManagerInterface, CategorizingPluginManagerInterface, FilteredPluginManagerInterface {
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ use Drupal\Core\Executable\ExecutableManagerInterface;
|
|||
use Drupal\Core\Executable\ExecutableInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\CategorizingPluginManagerTrait;
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerInterface;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* A plugin manager for condition plugins.
|
||||
|
@ -20,10 +21,10 @@ use Drupal\Core\Plugin\DefaultPluginManager;
|
|||
*
|
||||
* @ingroup plugin_api
|
||||
*/
|
||||
class ConditionManager extends DefaultPluginManager implements ExecutableManagerInterface, CategorizingPluginManagerInterface {
|
||||
class ConditionManager extends DefaultPluginManager implements ExecutableManagerInterface, CategorizingPluginManagerInterface, FilteredPluginManagerInterface {
|
||||
|
||||
use CategorizingPluginManagerTrait;
|
||||
use ContextAwarePluginManagerTrait;
|
||||
use FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Constructs a ConditionManager object.
|
||||
|
@ -43,6 +44,13 @@ class ConditionManager extends DefaultPluginManager implements ExecutableManager
|
|||
parent::__construct('Plugin/Condition', $namespaces, $module_handler, 'Drupal\Core\Condition\ConditionInterface', 'Drupal\Core\Condition\Annotation\Condition');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType() {
|
||||
return 'condition';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -12,12 +12,15 @@ use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
|
|||
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
|
||||
use Drupal\Core\Plugin\Discovery\YamlDiscoveryDecorator;
|
||||
use Drupal\Core\Layout\Annotation\Layout;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Provides a plugin manager for layouts.
|
||||
*/
|
||||
class LayoutPluginManager extends DefaultPluginManager implements LayoutPluginManagerInterface {
|
||||
|
||||
use FilteredPluginManagerTrait;
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
|
@ -42,8 +45,16 @@ class LayoutPluginManager extends DefaultPluginManager implements LayoutPluginMa
|
|||
parent::__construct('Plugin/Layout', $namespaces, $module_handler, LayoutInterface::class, Layout::class);
|
||||
$this->themeHandler = $theme_handler;
|
||||
|
||||
$this->setCacheBackend($cache_backend, 'layout');
|
||||
$this->alterInfo('layout');
|
||||
$type = $this->getType();
|
||||
$this->setCacheBackend($cache_backend, $type);
|
||||
$this->alterInfo($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType() {
|
||||
return 'layout';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
namespace Drupal\Core\Layout;
|
||||
|
||||
use Drupal\Component\Plugin\CategorizingPluginManagerInterface;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides the interface for a plugin manager of layouts.
|
||||
*/
|
||||
interface LayoutPluginManagerInterface extends CategorizingPluginManagerInterface {
|
||||
interface LayoutPluginManagerInterface extends CategorizingPluginManagerInterface, FilteredPluginManagerInterface {
|
||||
|
||||
/**
|
||||
* Gets theme implementations for layouts.
|
||||
|
|
|
@ -20,6 +20,8 @@ interface ContextAwarePluginManagerInterface extends PluginManagerInterface {
|
|||
*
|
||||
* @return array
|
||||
* An array of plugin definitions.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\FilteredPluginManagerInterface::getFilteredDefinitions()
|
||||
*/
|
||||
public function getDefinitionsForContexts(array $contexts = []);
|
||||
|
||||
|
|
|
@ -17,7 +17,9 @@ class ContextHandler implements ContextHandlerInterface {
|
|||
public function filterPluginDefinitionsByContexts(array $contexts, array $definitions) {
|
||||
return array_filter($definitions, function ($plugin_definition) use ($contexts) {
|
||||
// If this plugin doesn't need any context, it is available to use.
|
||||
if (!isset($plugin_definition['context'])) {
|
||||
// @todo Support object-based plugin definitions in
|
||||
// https://www.drupal.org/project/drupal/issues/2961822.
|
||||
if (!is_array($plugin_definition) || !isset($plugin_definition['context'])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Core\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for plugin managers that allow filtering definitions.
|
||||
*/
|
||||
interface FilteredPluginManagerInterface extends PluginManagerInterface {
|
||||
|
||||
/**
|
||||
* Gets the plugin definitions for a given type and consumer and filters them.
|
||||
*
|
||||
* This allows modules and themes to alter plugin definitions at runtime,
|
||||
* which is useful for tasks like hiding specific plugins from a particular
|
||||
* user interface.
|
||||
*
|
||||
* @param string $consumer
|
||||
* A string identifying the consumer of these plugin definitions.
|
||||
* @param \Drupal\Component\Plugin\Context\ContextInterface[]|null $contexts
|
||||
* (optional) Either an array of contexts to use for filtering, or NULL to
|
||||
* not filter by contexts.
|
||||
* @param mixed[] $extra
|
||||
* (optional) An associative array containing additional information
|
||||
* provided by the code requesting the filtered definitions.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Definition\PluginDefinitionInterface[]|array[]
|
||||
* An array of plugin definitions that are filtered.
|
||||
*
|
||||
* @see hook_plugin_filter_TYPE_alter()
|
||||
* @see hook_plugin_filter_TYPE__CONSUMER_alter()
|
||||
*/
|
||||
public function getFilteredDefinitions($consumer, $contexts = NULL, array $extra = []);
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Core\Plugin;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides a trait for plugin managers that allow filtering plugin definitions.
|
||||
*/
|
||||
trait FilteredPluginManagerTrait {
|
||||
|
||||
use ContextAwarePluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Plugin\FilteredPluginManagerInterface::getFilteredDefinitions().
|
||||
*/
|
||||
public function getFilteredDefinitions($consumer, $contexts = NULL, array $extra = []) {
|
||||
if (!is_null($contexts)) {
|
||||
$definitions = $this->getDefinitionsForContexts($contexts);
|
||||
}
|
||||
else {
|
||||
$definitions = $this->getDefinitions();
|
||||
}
|
||||
|
||||
$type = $this->getType();
|
||||
$hooks = [];
|
||||
$hooks[] = "plugin_filter_{$type}";
|
||||
$hooks[] = "plugin_filter_{$type}__{$consumer}";
|
||||
$this->moduleHandler()->alter($hooks, $definitions, $extra, $consumer);
|
||||
$this->themeManager()->alter($hooks, $definitions, $extra, $consumer);
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string identifying the plugin type.
|
||||
*
|
||||
* This string should be unique and generally will correspond to the string
|
||||
* used by the discovery, e.g. the annotation class or the YAML file name.
|
||||
*
|
||||
* @return string
|
||||
* A string identifying the plugin type.
|
||||
*/
|
||||
abstract protected function getType();
|
||||
|
||||
/**
|
||||
* Wraps the module handler.
|
||||
*
|
||||
* @return \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
* The module handler.
|
||||
*/
|
||||
protected function moduleHandler() {
|
||||
if (property_exists($this, 'moduleHandler') && $this->moduleHandler instanceof ModuleHandlerInterface) {
|
||||
return $this->moduleHandler;
|
||||
}
|
||||
|
||||
return \Drupal::service('module_handler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the theme manager.
|
||||
*
|
||||
* @return \Drupal\Core\Theme\ThemeManagerInterface
|
||||
* The theme manager.
|
||||
*/
|
||||
protected function themeManager() {
|
||||
if (property_exists($this, 'themeManager') && $this->themeManager instanceof ThemeManagerInterface) {
|
||||
return $this->themeManager;
|
||||
}
|
||||
|
||||
return \Drupal::service('theme.manager');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Plugin system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Alter the filtering of plugin definitions for a specific plugin type.
|
||||
*
|
||||
* TYPE (e.g. "block", "layout") limits hook scope to a plugin type.
|
||||
* For example, HOOK_plugin_filter_block_alter() would be invoked
|
||||
* by a hook listener which specifies the 'block' plugin list,
|
||||
* e.g., BlockLibraryController or ChooseBlockController.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Definition\PluginDefinitionInterface[]|array[] $definitions
|
||||
* The array of plugin definitions.
|
||||
* @param mixed[] $extra
|
||||
* An associative array containing additional information provided by the code
|
||||
* requesting the filtered definitions.
|
||||
* @param string $consumer
|
||||
* A string identifying the consumer of these plugin definitions.
|
||||
*/
|
||||
function hook_plugin_filter_TYPE_alter(array &$definitions, array $extra, $consumer) {
|
||||
// Remove the "Help" block from the Block UI list.
|
||||
if ($consumer == 'block_ui') {
|
||||
unset($definitions['help_block']);
|
||||
}
|
||||
|
||||
// If the theme is specified, remove the branding block from the Bartik theme.
|
||||
if (isset($extra['theme']) && $extra['theme'] === 'bartik') {
|
||||
unset($definitions['system_branding_block']);
|
||||
}
|
||||
|
||||
// Remove the "Main page content" block from everywhere.
|
||||
unset($definitions['system_main_block']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the filtering of plugin definitions for a specific type and consumer.
|
||||
*
|
||||
* TYPE (e.g. "block", "layout") limits hook scope to a plugin type.
|
||||
* CONSUMER (e.g., "block_ui", "layout_builder") limits hook scope to one or
|
||||
* more listeners, typically provided the same module. For example,
|
||||
* HOOK_plugin_filter_layout__layout_builder_alter() would affect
|
||||
* Layout Builder's listeners for the 'layout' plugin type (see
|
||||
* ChooseSectionController), while HOOK_plugin_filter_block__block_ui_alter()
|
||||
* would affect the Block UI's listeners for the 'block' plugin type.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Definition\PluginDefinitionInterface[]|array[] $definitions
|
||||
* The array of plugin definitions.
|
||||
* @param mixed[] $extra
|
||||
* An associative array containing additional information provided by the code
|
||||
* requesting the filtered definitions.
|
||||
*/
|
||||
function hook_plugin_filter_TYPE__CONSUMER_alter(array &$definitions, array $extra) {
|
||||
// Explicitly remove the "Help" block for this consumer.
|
||||
unset($definitions['help_block']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
|
@ -239,7 +239,8 @@ class BlockForm extends EntityForm {
|
|||
// @todo Allow list of conditions to be configured in
|
||||
// https://www.drupal.org/node/2284687.
|
||||
$visibility = $this->entity->getVisibility();
|
||||
foreach ($this->manager->getDefinitionsForContexts($form_state->getTemporaryValue('gathered_contexts')) as $condition_id => $definition) {
|
||||
$definitions = $this->manager->getFilteredDefinitions('block_ui', $form_state->getTemporaryValue('gathered_contexts'), ['block' => $this->entity]);
|
||||
foreach ($definitions as $condition_id => $definition) {
|
||||
// Don't display the current theme condition.
|
||||
if ($condition_id == 'current_theme') {
|
||||
continue;
|
||||
|
|
|
@ -101,8 +101,14 @@ class BlockLibraryController extends ControllerBase {
|
|||
['data' => $this->t('Operations')],
|
||||
];
|
||||
|
||||
$region = $request->query->get('region');
|
||||
$weight = $request->query->get('weight');
|
||||
|
||||
// Only add blocks which work without any available context.
|
||||
$definitions = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
|
||||
$definitions = $this->blockManager->getFilteredDefinitions('block_ui', $this->contextRepository->getAvailableContexts(), [
|
||||
'theme' => $theme,
|
||||
'region' => $region,
|
||||
]);
|
||||
// Order by category, and then by admin label.
|
||||
$definitions = $this->blockManager->getSortedDefinitions($definitions);
|
||||
// Filter out definitions that are not intended to be placed by the UI.
|
||||
|
@ -110,8 +116,6 @@ class BlockLibraryController extends ControllerBase {
|
|||
return empty($definition['_block_ui_hidden']);
|
||||
});
|
||||
|
||||
$region = $request->query->get('region');
|
||||
$weight = $request->query->get('weight');
|
||||
$rows = [];
|
||||
foreach ($definitions as $plugin_id => $plugin_definition) {
|
||||
$row = [];
|
||||
|
|
|
@ -63,7 +63,10 @@ class ChooseBlockController implements ContainerInjectionInterface {
|
|||
$build['#type'] = 'container';
|
||||
$build['#attributes']['class'][] = 'block-categories';
|
||||
|
||||
$definitions = $this->blockManager->getDefinitionsForContexts($this->getAvailableContexts($section_storage));
|
||||
$definitions = $this->blockManager->getFilteredDefinitions('layout_builder', $this->getAvailableContexts($section_storage), [
|
||||
'section_storage' => $section_storage,
|
||||
'region' => $region,
|
||||
]);
|
||||
foreach ($this->blockManager->getGroupedDefinitions($definitions) as $category => $blocks) {
|
||||
$build[$category]['#type'] = 'details';
|
||||
$build[$category]['#open'] = TRUE;
|
||||
|
|
|
@ -62,7 +62,8 @@ class ChooseSectionController implements ContainerInjectionInterface {
|
|||
$output['#title'] = $this->t('Choose a layout');
|
||||
|
||||
$items = [];
|
||||
foreach ($this->layoutManager->getDefinitions() as $plugin_id => $definition) {
|
||||
$definitions = $this->layoutManager->getFilteredDefinitions('layout_builder', [], ['section_storage' => $section_storage]);
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
$layout = $this->layoutManager->createInstance($plugin_id);
|
||||
$item = [
|
||||
'#type' => 'link',
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Layout Builder test'
|
||||
type: module
|
||||
description: 'Support module for testing layout building.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides hook implementations for Layout Builder tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_plugin_filter_TYPE__CONSUMER_alter().
|
||||
*/
|
||||
function layout_builder_test_plugin_filter_block__layout_builder_alter(array &$definitions) {
|
||||
// Explicitly remove the "Help" blocks from the list.
|
||||
unset($definitions['help_block']);
|
||||
|
||||
// Explicitly remove the "Sticky at top of lists field_block".
|
||||
$disallowed_fields = [
|
||||
'sticky',
|
||||
];
|
||||
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
// Field block IDs are in the form 'field_block:{entity}:{bundle}:{name}',
|
||||
// for example 'field_block:node:article:revision_timestamp'.
|
||||
preg_match('/field_block:.*:.*:(.*)/', $plugin_id, $parts);
|
||||
if (isset($parts[1]) && in_array($parts[1], $disallowed_fields, TRUE)) {
|
||||
// Unset any field blocks that match our predefined list.
|
||||
unset($definitions[$plugin_id]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
'layout_test',
|
||||
'block',
|
||||
'node',
|
||||
'layout_builder_test',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -319,4 +320,33 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$this->clickLink('Cancel Layout');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testLayoutBuilderChooseBlocksAlter() {
|
||||
// See layout_builder_test_plugin_filter_block__layout_builder_alter().
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'configure any layout',
|
||||
'administer node display',
|
||||
'administer node fields',
|
||||
]));
|
||||
|
||||
// From the manage display page, go to manage the layout.
|
||||
$this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display/default');
|
||||
$this->clickLink('Manage layout');
|
||||
|
||||
// Add a new block.
|
||||
$this->clickLink('Add Block');
|
||||
|
||||
// Verify that blocks not modified are present.
|
||||
$assert_session->linkExists('Powered by Drupal');
|
||||
$assert_session->linkExists('Default revision');
|
||||
|
||||
// Verify that blocks explicitly removed are not present.
|
||||
$assert_session->linkNotExists('Help');
|
||||
$assert_session->linkNotExists('Sticky at top of lists');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Core\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerBase;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerInterface;
|
||||
use Drupal\Core\Plugin\FilteredPluginManagerTrait;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Plugin\FilteredPluginManagerTrait
|
||||
* @group Plugin
|
||||
*/
|
||||
class FilteredPluginManagerTraitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::getFilteredDefinitions
|
||||
* @dataProvider providerTestGetFilteredDefinitions
|
||||
*/
|
||||
public function testGetFilteredDefinitions($contexts, $expected) {
|
||||
// Start with two plugins.
|
||||
$definitions = [];
|
||||
$definitions['plugin1'] = ['id' => 'plugin1'];
|
||||
$definitions['plugin2'] = ['id' => 'plugin2'];
|
||||
|
||||
$type = 'the_type';
|
||||
$consumer = 'the_consumer';
|
||||
$extra = ['foo' => 'bar'];
|
||||
|
||||
$context_handler = $this->prophesize(ContextHandlerInterface::class);
|
||||
// Remove the second plugin when context1 is provided.
|
||||
$context_handler->filterPluginDefinitionsByContexts(['context1' => 'fake context'], $definitions)
|
||||
->willReturn(['plugin1' => $definitions['plugin1']]);
|
||||
// Remove the first plugin when no contexts are provided.
|
||||
$context_handler->filterPluginDefinitionsByContexts([], $definitions)
|
||||
->willReturn(['plugin2' => $definitions['plugin2']]);
|
||||
|
||||
// After context filtering, the alter hook will be invoked.
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$hooks = ["plugin_filter_{$type}", "plugin_filter_{$type}__{$consumer}"];
|
||||
$module_handler->alter($hooks, $expected, $extra, $consumer)->shouldBeCalled();
|
||||
|
||||
$theme_manager = $this->prophesize(ThemeManagerInterface::class);
|
||||
$theme_manager->alter($hooks, $expected, $extra, $consumer)->shouldBeCalled();
|
||||
|
||||
$plugin_manager = new TestFilteredPluginManager($definitions, $module_handler->reveal(), $theme_manager->reveal(), $context_handler->reveal());
|
||||
$result = $plugin_manager->getFilteredDefinitions($consumer, $contexts, $extra);
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for ::testGetFilteredDefinitions().
|
||||
*/
|
||||
public function providerTestGetFilteredDefinitions() {
|
||||
$data = [];
|
||||
$data['populated context'] = [
|
||||
['context1' => 'fake context'],
|
||||
['plugin1' => ['id' => 'plugin1']],
|
||||
];
|
||||
$data['empty context'] = [
|
||||
[],
|
||||
['plugin2' => ['id' => 'plugin2']],
|
||||
];
|
||||
$data['null context'] = [
|
||||
NULL,
|
||||
[
|
||||
'plugin1' => ['id' => 'plugin1'],
|
||||
'plugin2' => ['id' => 'plugin2'],
|
||||
],
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that allows testing the trait.
|
||||
*/
|
||||
class TestFilteredPluginManager extends PluginManagerBase implements FilteredPluginManagerInterface {
|
||||
|
||||
use FilteredPluginManagerTrait;
|
||||
|
||||
protected $definitions = [];
|
||||
|
||||
protected $moduleHandler;
|
||||
|
||||
protected $themeManager;
|
||||
|
||||
protected $contextHandler;
|
||||
|
||||
public function __construct(array $definitions, ModuleHandlerInterface $module_handler, ThemeManagerInterface $theme_manager, ContextHandlerInterface $context_handler) {
|
||||
$this->definitions = $definitions;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->themeManager = $theme_manager;
|
||||
$this->contextHandler = $context_handler;
|
||||
}
|
||||
|
||||
protected function contextHandler() {
|
||||
return $this->contextHandler;
|
||||
}
|
||||
|
||||
protected function moduleHandler() {
|
||||
return $this->moduleHandler;
|
||||
}
|
||||
|
||||
protected function themeManager() {
|
||||
return $this->themeManager;
|
||||
}
|
||||
|
||||
protected function getType() {
|
||||
return 'the_type';
|
||||
}
|
||||
|
||||
public function getDefinitions() {
|
||||
return $this->definitions;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue