ImportStorageTransformer.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <?php
  2. namespace Drupal\Core\Config;
  3. use Drupal\Core\Database\Connection;
  4. use Drupal\Core\Lock\LockBackendInterface;
  5. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  6. /**
  7. * The import storage transformer helps to use the configuration management api.
  8. *
  9. * This service does not implement an interface and is final because it is not
  10. * meant to be replaced, extended or used in a different context.
  11. * Its single purpose is to transform a storage for the import step of a
  12. * configuration synchronization by dispatching the import transformation event.
  13. */
  14. final class ImportStorageTransformer {
  15. use StorageCopyTrait;
  16. /**
  17. * The name used to identify the lock.
  18. */
  19. const LOCK_NAME = 'config_import_transformer';
  20. /**
  21. * The event dispatcher to get changes to the configuration.
  22. *
  23. * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
  24. */
  25. protected $eventDispatcher;
  26. /**
  27. * The drupal database connection.
  28. *
  29. * @var \Drupal\Core\Database\Connection
  30. */
  31. protected $connection;
  32. /**
  33. * The normal lock for the duration of the request.
  34. *
  35. * @var \Drupal\Core\Lock\LockBackendInterface
  36. */
  37. protected $requestLock;
  38. /**
  39. * The persistent lock which the config importer uses across requests.
  40. *
  41. * @see \Drupal\Core\Config\ConfigImporter::alreadyImporting()
  42. *
  43. * @var \Drupal\Core\Lock\LockBackendInterface
  44. */
  45. protected $persistentLock;
  46. /**
  47. * ImportStorageTransformer constructor.
  48. *
  49. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
  50. * The event dispatcher.
  51. * @param \Drupal\Core\Database\Connection $connection
  52. * The database connection.
  53. * @param \Drupal\Core\Lock\LockBackendInterface $requestLock
  54. * The lock for the request.
  55. * @param \Drupal\Core\Lock\LockBackendInterface $persistentLock
  56. * The persistent lock used by the config importer.
  57. */
  58. public function __construct(EventDispatcherInterface $event_dispatcher, Connection $connection, LockBackendInterface $requestLock, LockBackendInterface $persistentLock) {
  59. $this->eventDispatcher = $event_dispatcher;
  60. $this->connection = $connection;
  61. $this->requestLock = $requestLock;
  62. $this->persistentLock = $persistentLock;
  63. }
  64. /**
  65. * Transform the storage to be imported from.
  66. *
  67. * An import transformation is done before the config importer uses the
  68. * storage to synchronize the configuration. The transformation is also
  69. * done for displaying differences to review imports.
  70. * Importing in this context means the active drupal configuration is changed
  71. * with the ConfigImporter which may or may not be as part of the config
  72. * synchronization.
  73. *
  74. * @param \Drupal\Core\Config\StorageInterface $storage
  75. * The storage to transform for importing from it.
  76. *
  77. * @return \Drupal\Core\Config\StorageInterface
  78. * The transformed storage ready to be imported from.
  79. *
  80. * @throws \Drupal\Core\Config\StorageTransformerException
  81. * Thrown when the lock could not be acquired.
  82. */
  83. public function transform(StorageInterface $storage) {
  84. // We use a database storage to reduce the memory requirement.
  85. $mutable = new DatabaseStorage($this->connection, 'config_import');
  86. if (!$this->persistentLock->lockMayBeAvailable(ConfigImporter::LOCK_NAME)) {
  87. // If the config importer is already importing, the transformation will
  88. // always be the one the config importer is already using. This makes sure
  89. // that even if the storage changes the importer continues importing the
  90. // same configuration.
  91. return $mutable;
  92. }
  93. // Acquire a lock to ensure that the storage is not changed when a
  94. // concurrent request tries to transform the storage. The lock will be
  95. // released at the end of the request.
  96. if (!$this->requestLock->acquire(self::LOCK_NAME)) {
  97. $this->requestLock->wait(self::LOCK_NAME);
  98. if (!$this->requestLock->acquire(self::LOCK_NAME)) {
  99. throw new StorageTransformerException("Cannot acquire config import transformer lock.");
  100. }
  101. }
  102. // Copy the sync configuration to the created mutable storage.
  103. self::replaceStorageContents($storage, $mutable);
  104. // Dispatch the event so that event listeners can alter the configuration.
  105. $this->eventDispatcher->dispatch(ConfigEvents::STORAGE_TRANSFORM_IMPORT, new StorageTransformEvent($mutable));
  106. // Return the storage with the altered configuration.
  107. return $mutable;
  108. }
  109. }