diff --git a/core/core.services.yml b/core/core.services.yml index 54fbf157977747e091122796d92f1e651b037ab5..21a5a029b3390b8a991e7b504d326bac82624c9e 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1884,6 +1884,7 @@ services: - '@file_system' - '@Drupal\Core\Theme\Component\SchemaCompatibilityChecker' - '@Drupal\Core\Theme\Component\ComponentValidator' + - '@service_container' - '%app.root%' Drupal\Core\Theme\ComponentPluginManager: '@plugin.manager.sdc' Drupal\Core\Template\Loader\ComponentLoader: diff --git a/core/lib/Drupal/Core/Theme/ComponentPluginManager.php b/core/lib/Drupal/Core/Theme/ComponentPluginManager.php index a0c93317699fc8066a239e47949277c6b6f1101b..e69d32c74a5ce78ba9aeb28c0e30230bdd06b123 100644 --- a/core/lib/Drupal/Core/Theme/ComponentPluginManager.php +++ b/core/lib/Drupal/Core/Theme/ComponentPluginManager.php @@ -21,6 +21,7 @@ use Drupal\Core\Render\Component\Exception\ComponentNotFoundException; use Drupal\Core\Render\Component\Exception\IncompatibleComponentSchema; use Drupal\Core\Plugin\Discovery\DirectoryWithMetadataPluginDiscovery; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Defines a plugin manager to deal with components. @@ -62,6 +63,8 @@ class ComponentPluginManager extends DefaultPluginManager implements Categorizin * The compatibility checker. * @param \Drupal\Core\Theme\Component\ComponentValidator $componentValidator * The component validator. + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The container. * @param string $appRoot * The application root. */ @@ -75,6 +78,7 @@ public function __construct( protected FileSystemInterface $fileSystem, protected SchemaCompatibilityChecker $compatibilityChecker, protected ComponentValidator $componentValidator, + protected ContainerInterface $container, protected string $appRoot, ) { // We are skipping the call to the parent constructor to avoid initializing @@ -124,6 +128,21 @@ public function createInstance($plugin_id, array $configuration = []): Component } } + /** + * {@inheritdoc} + */ + public function getDefinitions(): array { + $twig_config = $this->container->getParameter('twig.config'); + $twig_debug = $twig_config['debug'] ?? NULL; + $twig_cache = $twig_config['cache'] ?? NULL; + if ($twig_debug === TRUE || $twig_cache === FALSE) { + $this->definitions = $this->findDefinitions(); + return $this->definitions; + } + + return parent::getDefinitions(); + } + /** * Gets a component for rendering. * diff --git a/core/modules/system/tests/modules/sdc_test_plugin_manager/sdc_test_plugin_manager.info.yml b/core/modules/system/tests/modules/sdc_test_plugin_manager/sdc_test_plugin_manager.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..621b13a6a1b62de19ae3427c967483edb596fa98 --- /dev/null +++ b/core/modules/system/tests/modules/sdc_test_plugin_manager/sdc_test_plugin_manager.info.yml @@ -0,0 +1,3 @@ +name: 'Components Plugin Manager Test' +type: module +package: Testing diff --git a/core/modules/system/tests/modules/sdc_test_plugin_manager/src/SdcTestPluginManagerServiceProvider.php b/core/modules/system/tests/modules/sdc_test_plugin_manager/src/SdcTestPluginManagerServiceProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..7523d5cd1664799ca89d02180341eda4eefc49f3 --- /dev/null +++ b/core/modules/system/tests/modules/sdc_test_plugin_manager/src/SdcTestPluginManagerServiceProvider.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\sdc_test_plugin_manager; + +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\DependencyInjection\ServiceProviderBase; + +use Drupal\sdc_test_plugin_manager\Theme\TestComponentPluginManager; + +/** + * Modifies the component plugin manager service. + */ +class SdcTestPluginManagerServiceProvider extends ServiceProviderBase { + + /** + * {@inheritdoc} + */ + public function alter(ContainerBuilder $container): void { + // Overrides plugin.manager.sdc class to facilitate testing. + if ($container->hasDefinition('plugin.manager.sdc')) { + $definition = $container->getDefinition('plugin.manager.sdc'); + $definition->setClass(TestComponentPluginManager::class); + } + } + +} diff --git a/core/modules/system/tests/modules/sdc_test_plugin_manager/src/Theme/TestComponentPluginManager.php b/core/modules/system/tests/modules/sdc_test_plugin_manager/src/Theme/TestComponentPluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..8834f691d467b228bf37a1366d1a41a5a3a9ff54 --- /dev/null +++ b/core/modules/system/tests/modules/sdc_test_plugin_manager/src/Theme/TestComponentPluginManager.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\sdc_test_plugin_manager\Theme; + +use Drupal\Component\DependencyInjection\ContainerInterface; +use Drupal\Component\Plugin\Discovery\DiscoveryInterface; +use Drupal\Core\Theme\ComponentPluginManager; + +/** + * Provides a test entity type manager. + */ +class TestComponentPluginManager extends ComponentPluginManager { + + /** + * Sets the discovery for the manager. + * + * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery + * The discovery object. + */ + public function setDiscovery(DiscoveryInterface $discovery): void { + $this->discovery = $discovery; + } + + /** + * Sets the container for the manager. + * + * @param \Drupal\Component\DependencyInjection\ContainerInterface $container + * The container object. + */ + public function setContainer(ContainerInterface $container): void { + $this->container = $container; + } + +} diff --git a/core/tests/Drupal/KernelTests/Components/ComponentPluginManagerTest.php b/core/tests/Drupal/KernelTests/Components/ComponentPluginManagerTest.php index 1f110e36b4b5df6aa3e0b2f088680413ab7dd753..5b689c81cff7d780c9af7a874951e3b9fcc7e5ff 100644 --- a/core/tests/Drupal/KernelTests/Components/ComponentPluginManagerTest.php +++ b/core/tests/Drupal/KernelTests/Components/ComponentPluginManagerTest.php @@ -4,6 +4,8 @@ namespace Drupal\KernelTests\Components; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Plugin\Discovery\DirectoryWithMetadataPluginDiscovery; use Drupal\Core\Render\Component\Exception\ComponentNotFoundException; /** @@ -16,7 +18,12 @@ class ComponentPluginManagerTest extends ComponentKernelTestBase { /** * {@inheritdoc} */ - protected static $modules = ['system', 'sdc_test', 'sdc_test_replacements']; + protected static $modules = [ + 'system', + 'sdc_test', + 'sdc_test_replacements', + 'sdc_test_plugin_manager', + ]; /** * {@inheritdoc} @@ -49,4 +56,64 @@ public function testMismatchingFolderName(): void { $this->manager->find('sdc_theme_test:mismatching-folder-name'); } + /** + * Test component definitions caching depending on twig debug/cache settings. + * + * @param bool $twigDebug + * Whether twig debug is enabled. + * @param bool $cacheEnabled + * Whether cache is enabled. + * @param bool $expectCached + * Whether we expect the definitions are cached or not. + * + * @dataProvider providerTestComponentCachingDependingOnDevelopmentSettings + */ + public function testComponentCachingDependingOnDevelopmentSettings(bool $twigDebug, bool $cacheEnabled, bool $expectCached): void { + // Set the manager to a local variable, so we can type hint it. + /** @var \Drupal\sdc_test_plugin_manager\Theme\TestComponentPluginManager $manager */ + $manager = $this->manager; + + $firstObtainedDefinitions = $manager->getDefinitions(); + + // Set a mock discovery in the manager. + $discovery = $this->createMock(DirectoryWithMetadataPluginDiscovery::class); + $discovery->method('getDefinitions') + ->willReturn(array_slice($firstObtainedDefinitions, 0, -1, TRUE)); + $manager->setDiscovery($discovery); + + // Set a mock container in the manager. + $container = $this->createMock(ContainerBuilder::class); + $container->method('getParameter') + ->with('twig.config') + ->willReturn([ + 'debug' => $twigDebug, + 'cache' => $cacheEnabled, + ]); + $manager->setContainer($container); + + // Assert over definition keys, since it's the cleanest + // way to check if the definitions are the same after we + // removed one of them. + $firstObtainedDefinitionKeys = array_keys($firstObtainedDefinitions); + $secondObtainedDefinitionKeys = array_keys($manager->getDefinitions()); + if ($expectCached) { + $this->assertEquals($firstObtainedDefinitionKeys, $secondObtainedDefinitionKeys); + } + else { + $this->assertNotEquals($firstObtainedDefinitionKeys, $secondObtainedDefinitionKeys); + } + } + + /** + * Data provider for testComponentCachingDependingOnDevelopmentSettings(). + */ + public static function providerTestComponentCachingDependingOnDevelopmentSettings(): array { + return [ + 'Debug enabled, cache enabled' => [TRUE, TRUE, FALSE], + 'Debug enabled, cache disabled' => [TRUE, FALSE, FALSE], + 'Debug disabled, cache enabled' => [FALSE, TRUE, TRUE], + 'Debug disabled, cache disabled' => [FALSE, FALSE, FALSE], + ]; + } + }