cache_entity_type-1.x-dev/src/CacheEntityTypeServiceProvider.php
src/CacheEntityTypeServiceProvider.php
<?php
declare(strict_types=1);
namespace Drupal\cache_entity_type;
use Drupal\cache_entity_type\Entity\Cache\CacheBinNameFactory;
use Drupal\cache_entity_type\Entity\Cache\CacheEntityStorage;
use Drupal\cache_entity_type\Utility\ClassInheritance;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Creates cache bins for all entity types that use the "CacheEntityStorage" as storage backend.
*
* Only checks for entity types that use the "EntityType" annotation.
*
* @package Drupal\cache_entity_type
*/
class CacheEntityTypeServiceProvider extends ServiceProviderBase {
/**
* Discovers all entity type classes.
*
* Classes that are inside the src/Entity directory.
* And have the @EntityType annotation.
*
* Basically does the same as it is done in the Entity Type Manager.
* See \Drupal\Core\Entity\EntityTypeManager::__construct().
*
* @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
* The DI container builder.
*
* @return \Drupal\Core\Entity\EntityTypeInterface[]
* Entity type definitions.
*/
protected function discoverEntityTypeDefinitions(ContainerBuilder $container) {
$containerNamespacesArray = $container->getParameter('container.namespaces');
if (!is_array($containerNamespacesArray)) {
throw new \InvalidArgumentException('The container.namespaces parameter is not an array.');
}
$namespaces = new \ArrayObject($containerNamespacesArray);
$entityTypeClassDiscovery = new AnnotatedClassDiscovery('Entity', $namespaces, EntityType::class);
return $entityTypeClassDiscovery->getDefinitions();
}
/**
* Returns the cache entity type IDs contained in given definitions.
*
* @param \Drupal\Core\Entity\EntityTypeInterface[] $entityTypeDefinitions
* Entity type definitions.
*
* @return string[]
* Cache entity type IDs.
*/
protected function selectCacheEntityTypeIds(array $entityTypeDefinitions): array {
$cacheEntityTypeIds = [];
foreach ($entityTypeDefinitions as $entityTypeDefinition) {
$storageHandlerClassName = $entityTypeDefinition->getHandlerClass('storage');
if (!is_string($storageHandlerClassName)) {
continue;
}
if (ClassInheritance::isSameOrDoesExtend($storageHandlerClassName, CacheEntityStorage::class)) {
$cacheEntityTypeIds[] = $entityTypeDefinition->id();
}
}
return $cacheEntityTypeIds;
}
/**
* Creates a cache bin service definition.
*
* @param string $binName
* The name of the cache bin.
*
* @return \Symfony\Component\DependencyInjection\Definition
* The cache bin service definition.
*/
protected function createCacheBinServiceDefinition(string $binName): Definition {
$serviceDefinition = new Definition(CacheBackendInterface::class);
$serviceDefinition->addTag('cache.bin');
$serviceDefinition->setFactory([new Reference('cache_factory'), 'get']);
$serviceDefinition->addArgument(CacheBinNameFactory::binName($binName));
return $serviceDefinition;
}
/**
* Entity cache bins have to be tagged to ensure they are included on a Drupal cache clear.
*
* They are discovered via the "cache.bin" service tag.
* See \Drupal\Core\Cache\ListCacheBinsPass::process().
*
* @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
* The container builder.
*
* @phpstan-ignore-next-line
*/
public function register(ContainerBuilder $container) {
parent::register($container);
$entityTypeDefinitions = $this->discoverEntityTypeDefinitions($container);
$cacheEntityTypeIds = $this->selectCacheEntityTypeIds($entityTypeDefinitions);
foreach ($cacheEntityTypeIds as $cacheEntityTypeId) {
$cacheBinServiceId = CacheBinNameFactory::binServiceName($cacheEntityTypeId);
/* We do not want to override already defined cache bins.
In case a custom bin configuration is used for an entity type. */
if (!$container->hasDefinition($cacheBinServiceId)) {
$container->setDefinition($cacheBinServiceId, $this->createCacheBinServiceDefinition($cacheEntityTypeId));
}
}
}
}
