Verified Commit 0b166211 authored by godotislate's avatar godotislate
Browse files

task: #2951046 Allow parsing and writing PHP class constants and enums in YAML files

By: marcoscano
By: dawehner
By: amateescu
By: alexpott
By: andypost
By: neclimdul
By: gapple
By: narendrar
By: mikelutz
By: longwave
By: phenaproxima
By: mondrake
By: eduardo morales alberti
By: wim leers
By: dcam
By: borisson_
By: bircher
By: catch
By: kristiaanvandeneynde
By: godotislate
(cherry picked from commit 2884bf37)
parent 53d8bd89
Loading
Loading
Loading
Loading
Loading
+3 −0
Changes for core/config/schema/core.data_types.schema.yml: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@ ignore:
boolean:
  label: 'Boolean'
  class: '\Drupal\Core\TypedData\Plugin\DataType\BooleanData'
enum:
  label: 'Enum'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Enum'
email:
  label: 'Email'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Email'
+5 −2
Changes for core/core.services.yml: 5 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -476,8 +476,11 @@ services:
    public: false
  Drupal\Core\Config\StorageManagerInterface: '@config.storage.export.manager'
  config.storage.sync:
    class: Drupal\Core\Config\FileStorage
    factory: Drupal\Core\Config\FileStorageFactory::getSync
    class: Drupal\Core\Config\AutoloadingStorage
    factory: ['@Drupal\Core\Config\SyncFactory', 'get']
  Drupal\Core\Config\SyncFactory:
    autowire: true
    public: false
  config.storage.snapshot:
    class: Drupal\Core\Config\DatabaseStorage
    arguments: ['@database', config_snapshot]
+1 −1
Changes for core/lib/Drupal/Component/Serialization/Yaml.php: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ public static function decode($raw) {
      // 'foo: bar' with no newline will fail to parse otherwise.
      return $yaml->parse(
        $raw,
        SymfonyYaml::PARSE_EXCEPTION_ON_INVALID_TYPE | SymfonyYaml::PARSE_CUSTOM_TAGS
        SymfonyYaml::PARSE_EXCEPTION_ON_INVALID_TYPE | SymfonyYaml::PARSE_CUSTOM_TAGS | SymfonyYaml::PARSE_CONSTANT
      );
    }
    catch (\Exception $e) {
+163 −0
Changes for core/lib/Drupal/Core/Config/AutoloadingStorage.php: 163 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Config;

use Composer\Autoload\ClassLoader;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;

/**
 * Defines the autoloading storage.
 *
 * Allows configuration to be read that contains constants and enum from
 * extensions that are not yet installed. To do so, a class loader is
 * temporarily registered while reading from configuration.
 */
class AutoloadingStorage implements StorageInterface, StorageCacheInterface {

  use DependencySerializationTrait;

  /**
   * Class loader that loads code from extensions provided to the constructor.
   */
  protected ?ClassLoader $classloader = NULL;

  /**
   * Constructs a new AutoloadingStorage.
   *
   * @param \Drupal\Core\Config\StorageInterface $storage
   *   A configuration storage to be wrapped.
   * @param string[] $newExtensions
   *   A list of new extensions in the source storage that we need to allow to
   *   autoload while reading. The values should be absolute paths to the
   *   extension directory.
   */
  public function __construct(protected StorageInterface $storage, array $newExtensions = []) {
    if (!empty($newExtensions)) {
      $this->classloader = new ClassLoader();
      foreach ($newExtensions as $extension => $dir) {
        $this->classloader->addPsr4("Drupal\\$extension\\", $dir . '/src');
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function exists($name): bool {
    return $this->storage->exists($name);
  }

  /**
   * {@inheritdoc}
   */
  public function read($name): array|false {
    $this->classloader?->register(TRUE);
    try {
      $data = $this->storage->read($name);
    }
    finally {
      $this->classloader?->unregister();
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function readMultiple(array $names): array {
    $this->classloader?->register(TRUE);
    try {
      $data = $this->storage->readMultiple($names);
    }
    finally {
      $this->classloader?->unregister();
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function write($name, array $data): bool {
    return $this->storage->write($name, $data);
  }

  /**
   * {@inheritdoc}
   */
  public function delete($name): bool {
    return $this->storage->delete($name);
  }

  /**
   * {@inheritdoc}
   */
  public function rename($name, $new_name): bool {
    return $this->storage->rename($name, $new_name);
  }

  /**
   * {@inheritdoc}
   */
  public function encode($data): string {
    return $this->storage->encode($data);
  }

  /**
   * {@inheritdoc}
   */
  public function decode($raw): array {
    return $this->storage->decode($raw);
  }

  /**
   * {@inheritdoc}
   */
  public function listAll($prefix = ''): array {
    return $this->storage->listAll($prefix);
  }

  /**
   * {@inheritdoc}
   */
  public function deleteAll($prefix = ''): bool {
    return $this->storage->deleteAll($prefix);
  }

  /**
   * Clears the static list cache.
   */
  public function resetListCache(): void {
    if ($this->storage instanceof StorageCacheInterface) {
      $this->storage->resetListCache();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function createCollection($collection): static {
    $storage = new static(
      $this->storage->createCollection($collection)
    );
    $storage->classloader = $this->classloader;
    return $storage;
  }

  /**
   * {@inheritdoc}
   */
  public function getAllCollectionNames(): array {
    return $this->storage->getAllCollectionNames();
  }

  /**
   * {@inheritdoc}
   */
  public function getCollectionName(): string {
    return $this->storage->getCollectionName();
  }

}
+6 −0
Changes for core/lib/Drupal/Core/Config/ConfigInstaller.php: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -556,8 +556,10 @@ public function checkConfigurationToInstall($type, $name) {
    $names = (array) $name;
    $enabled_extensions = $this->getEnabledExtensions();
    $previous_config_names = [];
    $autoloader_paths = [];

    foreach ($names as $name) {
      $autoloader_paths[$name] = \Drupal::root() . '/' . $this->extensionPathResolver->getPath($type, $name);
      // Add the extension that will be enabled to the list of enabled
      // extensions.
      $enabled_extensions[] = $name;
@@ -572,6 +574,10 @@ public function checkConfigurationToInstall($type, $name) {
      // Gets profile storages to search for overrides if necessary.
      $profile_storages = $this->getProfileStorages($name);

      // Ensure enums and constants can be autoloaded from the module or its
      // dependencies being installed.
      $storage = new AutoloadingStorage($storage, $autoloader_paths);

      // Check the dependencies of configuration provided by the module.
      [
        $invalid_default_config,
Loading