Issue #3432827 by longwave: Use tagged iterator in plugin.cache_clearer instead of a lazy service

merge-requests/7825/merge
catch 2024-05-24 10:10:33 +01:00
parent d4e1e52ab2
commit 2d68d830b9
7 changed files with 44 additions and 119 deletions

View File

@ -865,7 +865,7 @@ services:
Drupal\Core\Queue\QueueWorkerManagerInterface: '@plugin.manager.queue_worker'
plugin.cache_clearer:
class: Drupal\Core\Plugin\CachedDiscoveryClearer
lazy: true
autowire: true
Drupal\Core\Plugin\CachedDiscoveryClearerInterface: '@plugin.cache_clearer'
paramconverter.menu_link:
class: Drupal\Core\ParamConverter\MenuLinkPluginConverter

View File

@ -3,6 +3,7 @@
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
/**
* Defines a class which is capable of clearing the cache on plugin managers.
@ -10,19 +11,43 @@ use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
class CachedDiscoveryClearer implements CachedDiscoveryClearerInterface {
/**
* The stored discoveries.
* The legacy stored discoveries.
*
* @var \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface[]
*
* @deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Pass
* the full set of services to the constructor instead.
* @see https://www.drupal.org/node/3442229
*/
protected $cachedDiscoveries = [];
protected $legacyCachedDiscoveries = [];
/**
* {@inheritdoc}
* Adds a plugin manager to the active list.
*
* @param \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $cached_discovery
* An object that implements the cached discovery interface, typically a
* plugin manager.
*
* @deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Pass
* the full set of services to the constructor instead.
* @see https://www.drupal.org/node/3442229
*/
public function addCachedDiscovery(CachedDiscoveryInterface $cached_discovery) {
$this->cachedDiscoveries[] = $cached_discovery;
@trigger_error('The ' . __METHOD__ . ' method is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Pass the full set of services to the constructor instead. See https://www.drupal.org/node/3442229', E_USER_DEPRECATED);
$this->legacyCachedDiscoveries[] = $cached_discovery;
}
/**
* Constructs the CachedDiscoveryClearer service.
*
* @param \Traversable $cachedDiscoveries
* The cached discoveries.
*/
public function __construct(
#[AutowireIterator(tag: 'plugin_manager_cache_clear')]
protected \Traversable $cachedDiscoveries,
) {}
/**
* {@inheritdoc}
*/
@ -30,6 +55,11 @@ class CachedDiscoveryClearer implements CachedDiscoveryClearerInterface {
foreach ($this->cachedDiscoveries as $cached_discovery) {
$cached_discovery->clearCachedDefinitions();
}
// @phpstan-ignore property.deprecated
foreach ($this->legacyCachedDiscoveries as $cached_discovery) {
$cached_discovery->clearCachedDefinitions();
}
}
}

View File

@ -2,22 +2,11 @@
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
/**
* Provides a way to clear static caches of all plugin managers.
*/
interface CachedDiscoveryClearerInterface {
/**
* Adds a plugin manager to the active list.
*
* @param \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $cached_discovery
* An object that implements the cached discovery interface, typically a
* plugin manager.
*/
public function addCachedDiscovery(CachedDiscoveryInterface $cached_discovery);
/**
* Clears the cache on all cached discoveries.
*/

View File

@ -4,7 +4,6 @@ namespace Drupal\Core\Plugin;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers plugin managers to the plugin.cache_clearer service.
@ -15,11 +14,10 @@ class PluginManagerPass implements CompilerPassInterface {
* {@inheritdoc}
*/
public function process(ContainerBuilder $container): void {
$cache_clearer_definition = $container->getDefinition('plugin.cache_clearer');
foreach ($container->getDefinitions() as $service_id => $definition) {
if (str_starts_with($service_id, 'plugin.manager.') || $definition->hasTag('plugin_manager_cache_clear')) {
if (str_starts_with($service_id, 'plugin.manager.') && !$definition->hasTag('plugin_manager_cache_clear')) {
if (is_subclass_of($definition->getClass(), '\Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface')) {
$cache_clearer_definition->addMethodCall('addCachedDiscovery', [new Reference($service_id)]);
$definition->addTag('plugin_manager_cache_clear');
}
}
}

View File

@ -1,88 +0,0 @@
<?php
// phpcs:ignoreFile
/**
* This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Plugin\CachedDiscoveryClearer' "core/lib/Drupal/Core".
*/
namespace Drupal\Core\ProxyClass\Plugin {
/**
* Provides a proxy class for \Drupal\Core\Plugin\CachedDiscoveryClearer.
*
* @see \Drupal\Component\ProxyBuilder
*/
class CachedDiscoveryClearer implements \Drupal\Core\Plugin\CachedDiscoveryClearerInterface
{
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
* The id of the original proxied service.
*
* @var string
*/
protected $drupalProxyOriginalServiceId;
/**
* The real proxied service, after it was lazy loaded.
*
* @var \Drupal\Core\Plugin\CachedDiscoveryClearer
*/
protected $service;
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructs a ProxyClass Drupal proxy object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param string $drupal_proxy_original_service_id
* The service ID of the original service.
*/
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
{
$this->container = $container;
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
}
/**
* Lazy loads the real service from the container.
*
* @return object
* Returns the constructed real service.
*/
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
}
return $this->service;
}
/**
* {@inheritdoc}
*/
public function addCachedDiscovery(\Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $cached_discovery)
{
return $this->lazyLoadItself()->addCachedDiscovery($cached_discovery);
}
/**
* {@inheritdoc}
*/
public function clearCachedDefinitions()
{
return $this->lazyLoadItself()->clearCachedDefinitions();
}
}
}

View File

@ -104,11 +104,7 @@ class EntityValidationTest extends EntityKernelTestBase {
// Use the protected property on the cache_clearer first to check whether
// the constraint manager is added there.
// Ensure that the proxy class is initialized, which has the necessary
// method calls attached.
\Drupal::service('plugin.cache_clearer');
$plugin_cache_clearer = \Drupal::service('drupal.proxy_original_service.plugin.cache_clearer');
$plugin_cache_clearer = \Drupal::service('plugin.cache_clearer');
$get_cached_discoveries = function () {
return $this->cachedDiscoveries;
};

View File

@ -37,12 +37,12 @@ class ProxyServicesPassTest extends UnitTestCase {
*/
public function testContainerWithoutLazyServices() {
$container = new ContainerBuilder();
$container->register('plugin_cache_clearer', 'Drupal\Core\Plugin\CachedDiscoveryClearer');
$container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend');
$this->proxyServicesPass->process($container);
$this->assertCount(2, $container->getDefinitions());
$this->assertEquals('Drupal\Core\Plugin\CachedDiscoveryClearer', $container->getDefinition('plugin_cache_clearer')->getClass());
$this->assertEquals('Drupal\Core\Lock\DatabaseLockBackend', $container->getDefinition('lock')->getClass());
}
/**
@ -50,19 +50,19 @@ class ProxyServicesPassTest extends UnitTestCase {
*/
public function testContainerWithLazyServices() {
$container = new ContainerBuilder();
$container->register('plugin_cache_clearer', 'Drupal\Core\Plugin\CachedDiscoveryClearer')
$container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend')
->setLazy(TRUE);
$this->proxyServicesPass->process($container);
$this->assertCount(3, $container->getDefinitions());
$non_proxy_definition = $container->getDefinition('drupal.proxy_original_service.plugin_cache_clearer');
$this->assertEquals('Drupal\Core\Plugin\CachedDiscoveryClearer', $non_proxy_definition->getClass());
$non_proxy_definition = $container->getDefinition('drupal.proxy_original_service.lock');
$this->assertEquals('Drupal\Core\Lock\DatabaseLockBackend', $non_proxy_definition->getClass());
$this->assertFalse($non_proxy_definition->isLazy());
$this->assertTrue($non_proxy_definition->isPublic());
$this->assertEquals('Drupal\Core\ProxyClass\Plugin\CachedDiscoveryClearer', $container->getDefinition('plugin_cache_clearer')->getClass());
$this->assertEquals('Drupal\Core\ProxyClass\Lock\DatabaseLockBackend', $container->getDefinition('lock')->getClass());
}
/**