Loading core/core.services.yml +8 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,14 @@ services: arguments: ['@config.storage', '@database', '@event_dispatcher', '@lock'] public: false Drupal\Core\Config\StorageManagerInterface: '@config.storage.export.manager' config.parsing_cache: class: Drupal\Core\Utility\YamlCacheCollector arguments: ['config.parsing_cache', '@cache.file_parsing', '@lock', '@datetime.time'] tags: - { name: needs_destruction } config.file_storage.factory: class: Drupal\Core\Config\FileStorageFactory Drupal\Core\Config\FileStorageFactory: '@config.file_storage.factory' config.storage.sync: class: Drupal\Core\Config\AutoloadingStorage factory: ['@Drupal\Core\Config\SyncFactory', 'get'] Loading core/lib/Drupal/Core/Config/FileStorage.php +34 −41 Original line number Diff line number Diff line Loading @@ -2,38 +2,18 @@ namespace Drupal\Core\Config; use Drupal\Component\FileCache\FileCacheFactory; use Drupal\Component\FileSecurity\FileSecurity; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\Core\Cache\CacheCollectorInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Serialization\Yaml; use Drupal\Core\Utility\YamlCacheCollector; /** * Defines the file storage. */ class FileStorage implements StorageInterface { /** * The storage collection. * * @var string */ protected $collection; /** * The filesystem path for configuration objects. * * @var string */ protected $directory = ''; /** * The file cache object. * * @var \Drupal\Component\FileCache\FileCacheInterface */ protected $fileCache; /** * Constructs a new FileStorage. * Loading @@ -42,14 +22,18 @@ class FileStorage implements StorageInterface { * @param string $collection * (optional) The collection to store configuration in. Defaults to the * default collection. * @param ?Drupal\Core\Cache\CacheCollectorInterface $yamlCacheCollector * The YAML cache collector. If not passed, a YAMl cache collector with * a memory backend will be used. */ public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) { $this->directory = $directory; $this->collection = $collection; // Use a NULL File Cache backend by default. This will ensure only the // internal static caching of FileCache is used and thus avoids blowing up // the APCu cache. $this->fileCache = FileCacheFactory::get('config', ['cache_backend_class' => NULL]); public function __construct( protected string $directory, protected string $collection = StorageInterface::DEFAULT_COLLECTION, protected ?CacheCollectorInterface $yamlCacheCollector = NULL, ) { if (!isset($yamlCacheCollector)) { $this->yamlCacheCollector = YamlCacheCollector::createWithMemoryCache(); } } /** Loading Loading @@ -106,18 +90,27 @@ public function read($name) { } $filepath = $this->getFilePath($name); if ($data = $this->fileCache->get($filepath)) { return $data; } $data = file_get_contents($filepath); // To support enums in YAML files, the config system implements a special // autoloader to load classes from extensions that may not be installed such // as before config sync. This autoloader has to be primed with the names of // extensions which are about to be installed. However, before doing that, // it has to read the extensions from core.extension. To avoid trying to // unserialize() enums which may not exist, avoid the YamlCacheCollector // when reading core.extension, this allows the autoloader to be set up // prior to the cache being unserialized. try { $data = $this->decode($data); if ($name === 'core.extension') { $data = file_get_contents($filepath); return Yaml::decode($data); } elseif ($data = $this->yamlCacheCollector->get($filepath)) { return is_array($data) ? $data : FALSE; } } catch (InvalidDataTypeException $e) { throw new UnsupportedDataTypeConfigException('Invalid data type in config ' . $name . ', found in file ' . $filepath . ': ' . $e->getMessage()); } $this->fileCache->set($filepath, $data); return $data; } Loading Loading @@ -156,8 +149,7 @@ public function write($name, array $data) { if ($status === FALSE) { throw new StorageException('Failed to write configuration file: ' . $target); } $this->fileCache->set($target, $data); $this->yamlCacheCollector->delete($target); return TRUE; } Loading @@ -169,7 +161,7 @@ public function delete($name) { if (!$this->exists($name)) { return FALSE; } $this->fileCache->delete($this->getFilePath($name)); $this->yamlCacheCollector->delete($this->getFilePath($name)); return $this->getFileSystem()->unlink($this->getFilePath($name)); } Loading @@ -181,8 +173,8 @@ public function rename($name, $new_name) { if ($status === FALSE) { return FALSE; } $this->fileCache->delete($this->getFilePath($name)); $this->fileCache->delete($this->getFilePath($new_name)); $this->yamlCacheCollector->delete($this->getFilePath($name)); $this->yamlCacheCollector->delete($this->getFilePath($new_name)); return TRUE; } Loading Loading @@ -258,7 +250,8 @@ public function deleteAll($prefix = '') { public function createCollection($collection) { return new static( $this->directory, $collection $collection, $this->yamlCacheCollector ); } Loading core/lib/Drupal/Core/Config/InstallStorage.php +0 −7 Original line number Diff line number Diff line Loading @@ -40,13 +40,6 @@ class InstallStorage extends FileStorage { */ protected $folders; /** * The directory to scan in each extension to scan for files. * * @var string */ protected $directory; /** * Constructs an InstallStorage object. * Loading core/lib/Drupal/Core/Config/SyncFactory.php +4 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Cache\CacheCollectorInterface; use Drupal\Core\Extension\Exception\UnknownExtensionException; use Drupal\Core\Extension\ExtensionList; use Drupal\Core\Extension\ModuleExtensionList; Loading @@ -24,6 +25,8 @@ public function __construct( protected readonly StorageInterface $activeConfig, protected readonly ModuleExtensionList $moduleExtensionList, protected readonly ThemeExtensionList $themeExtensionList, #[Autowire(service: 'config.parsing_cache')] protected readonly CacheCollectorInterface $yamlCacheCollector, ) { } Loading @@ -45,7 +48,7 @@ public function get(): StorageInterface { if ($directory === FALSE) { throw new ConfigDirectoryNotDefinedException('The config sync directory is not defined in $settings["config_sync_directory"]'); } $storage = new FileStorage($directory); $storage = new FileStorage($directory, StorageInterface::DEFAULT_COLLECTION, $this->yamlCacheCollector); return $this->wrapStorageWithAutoloadingStorage($storage); } Loading core/lib/Drupal/Core/Extension/ModuleInstaller.php +7 −0 Original line number Diff line number Diff line Loading @@ -646,6 +646,13 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { $cache_backend->deleteAll(); } // The config parsing cache isn't tagged as a cache bin because it is // designed to persist across cache clears. However when a module is // uninstalled we want to ensure that parsed configuration for that module // is also deleted, both to free up space and to avoid missing class // dependencies in the cache entry. \Drupal::service('config.parsing_cache')->clear(); return TRUE; } Loading Loading
core/core.services.yml +8 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,14 @@ services: arguments: ['@config.storage', '@database', '@event_dispatcher', '@lock'] public: false Drupal\Core\Config\StorageManagerInterface: '@config.storage.export.manager' config.parsing_cache: class: Drupal\Core\Utility\YamlCacheCollector arguments: ['config.parsing_cache', '@cache.file_parsing', '@lock', '@datetime.time'] tags: - { name: needs_destruction } config.file_storage.factory: class: Drupal\Core\Config\FileStorageFactory Drupal\Core\Config\FileStorageFactory: '@config.file_storage.factory' config.storage.sync: class: Drupal\Core\Config\AutoloadingStorage factory: ['@Drupal\Core\Config\SyncFactory', 'get'] Loading
core/lib/Drupal/Core/Config/FileStorage.php +34 −41 Original line number Diff line number Diff line Loading @@ -2,38 +2,18 @@ namespace Drupal\Core\Config; use Drupal\Component\FileCache\FileCacheFactory; use Drupal\Component\FileSecurity\FileSecurity; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\Core\Cache\CacheCollectorInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Serialization\Yaml; use Drupal\Core\Utility\YamlCacheCollector; /** * Defines the file storage. */ class FileStorage implements StorageInterface { /** * The storage collection. * * @var string */ protected $collection; /** * The filesystem path for configuration objects. * * @var string */ protected $directory = ''; /** * The file cache object. * * @var \Drupal\Component\FileCache\FileCacheInterface */ protected $fileCache; /** * Constructs a new FileStorage. * Loading @@ -42,14 +22,18 @@ class FileStorage implements StorageInterface { * @param string $collection * (optional) The collection to store configuration in. Defaults to the * default collection. * @param ?Drupal\Core\Cache\CacheCollectorInterface $yamlCacheCollector * The YAML cache collector. If not passed, a YAMl cache collector with * a memory backend will be used. */ public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) { $this->directory = $directory; $this->collection = $collection; // Use a NULL File Cache backend by default. This will ensure only the // internal static caching of FileCache is used and thus avoids blowing up // the APCu cache. $this->fileCache = FileCacheFactory::get('config', ['cache_backend_class' => NULL]); public function __construct( protected string $directory, protected string $collection = StorageInterface::DEFAULT_COLLECTION, protected ?CacheCollectorInterface $yamlCacheCollector = NULL, ) { if (!isset($yamlCacheCollector)) { $this->yamlCacheCollector = YamlCacheCollector::createWithMemoryCache(); } } /** Loading Loading @@ -106,18 +90,27 @@ public function read($name) { } $filepath = $this->getFilePath($name); if ($data = $this->fileCache->get($filepath)) { return $data; } $data = file_get_contents($filepath); // To support enums in YAML files, the config system implements a special // autoloader to load classes from extensions that may not be installed such // as before config sync. This autoloader has to be primed with the names of // extensions which are about to be installed. However, before doing that, // it has to read the extensions from core.extension. To avoid trying to // unserialize() enums which may not exist, avoid the YamlCacheCollector // when reading core.extension, this allows the autoloader to be set up // prior to the cache being unserialized. try { $data = $this->decode($data); if ($name === 'core.extension') { $data = file_get_contents($filepath); return Yaml::decode($data); } elseif ($data = $this->yamlCacheCollector->get($filepath)) { return is_array($data) ? $data : FALSE; } } catch (InvalidDataTypeException $e) { throw new UnsupportedDataTypeConfigException('Invalid data type in config ' . $name . ', found in file ' . $filepath . ': ' . $e->getMessage()); } $this->fileCache->set($filepath, $data); return $data; } Loading Loading @@ -156,8 +149,7 @@ public function write($name, array $data) { if ($status === FALSE) { throw new StorageException('Failed to write configuration file: ' . $target); } $this->fileCache->set($target, $data); $this->yamlCacheCollector->delete($target); return TRUE; } Loading @@ -169,7 +161,7 @@ public function delete($name) { if (!$this->exists($name)) { return FALSE; } $this->fileCache->delete($this->getFilePath($name)); $this->yamlCacheCollector->delete($this->getFilePath($name)); return $this->getFileSystem()->unlink($this->getFilePath($name)); } Loading @@ -181,8 +173,8 @@ public function rename($name, $new_name) { if ($status === FALSE) { return FALSE; } $this->fileCache->delete($this->getFilePath($name)); $this->fileCache->delete($this->getFilePath($new_name)); $this->yamlCacheCollector->delete($this->getFilePath($name)); $this->yamlCacheCollector->delete($this->getFilePath($new_name)); return TRUE; } Loading Loading @@ -258,7 +250,8 @@ public function deleteAll($prefix = '') { public function createCollection($collection) { return new static( $this->directory, $collection $collection, $this->yamlCacheCollector ); } Loading
core/lib/Drupal/Core/Config/InstallStorage.php +0 −7 Original line number Diff line number Diff line Loading @@ -40,13 +40,6 @@ class InstallStorage extends FileStorage { */ protected $folders; /** * The directory to scan in each extension to scan for files. * * @var string */ protected $directory; /** * Constructs an InstallStorage object. * Loading
core/lib/Drupal/Core/Config/SyncFactory.php +4 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Cache\CacheCollectorInterface; use Drupal\Core\Extension\Exception\UnknownExtensionException; use Drupal\Core\Extension\ExtensionList; use Drupal\Core\Extension\ModuleExtensionList; Loading @@ -24,6 +25,8 @@ public function __construct( protected readonly StorageInterface $activeConfig, protected readonly ModuleExtensionList $moduleExtensionList, protected readonly ThemeExtensionList $themeExtensionList, #[Autowire(service: 'config.parsing_cache')] protected readonly CacheCollectorInterface $yamlCacheCollector, ) { } Loading @@ -45,7 +48,7 @@ public function get(): StorageInterface { if ($directory === FALSE) { throw new ConfigDirectoryNotDefinedException('The config sync directory is not defined in $settings["config_sync_directory"]'); } $storage = new FileStorage($directory); $storage = new FileStorage($directory, StorageInterface::DEFAULT_COLLECTION, $this->yamlCacheCollector); return $this->wrapStorageWithAutoloadingStorage($storage); } Loading
core/lib/Drupal/Core/Extension/ModuleInstaller.php +7 −0 Original line number Diff line number Diff line Loading @@ -646,6 +646,13 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { $cache_backend->deleteAll(); } // The config parsing cache isn't tagged as a cache bin because it is // designed to persist across cache clears. However when a module is // uninstalled we want to ensure that parsed configuration for that module // is also deleted, both to free up space and to avoid missing class // dependencies in the cache entry. \Drupal::service('config.parsing_cache')->clear(); return TRUE; } Loading