PageRenderTime 65ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/core/lib/Drupal/Core/Config/ConfigImporter.php

https://bitbucket.org/aswinvk28/smartpan-stock-drupal
PHP | 326 lines | 120 code | 31 blank | 175 comment | 12 complexity | d2c2711afee7048e1dd5b9175c86d0db MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Core\Config\ConfigImporter.
  5. */
  6. namespace Drupal\Core\Config;
  7. use Drupal\Core\Lock\LockBackendInterface;
  8. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  9. /**
  10. * Defines a configuration importer.
  11. *
  12. * A config importer imports the changes into the configuration system. To
  13. * determine which changes to import a StorageComparer in used.
  14. *
  15. * @see \Drupal\Core\Config\StorageComparerInterface
  16. *
  17. * The ConfigImporter has a identifier which is used to construct event names.
  18. * The events fired during an import are:
  19. * - ConfigEvents::VALIDATE: Events listening can throw a
  20. * \Drupal\Core\Config\ConfigImporterException to prevent an import from
  21. * occurring.
  22. * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
  23. * - ConfigEvents::IMPORT: Events listening can react to a successful import.
  24. * @see \Drupal\Core\EventSubscriber\ConfigSnapshotSubscriber
  25. *
  26. * @see \Drupal\Core\Config\ConfigImporterEvent
  27. */
  28. class ConfigImporter {
  29. /**
  30. * The name used to identify events and the lock.
  31. */
  32. const ID = 'config.importer';
  33. /**
  34. * The storage comparer used to discover configuration changes.
  35. *
  36. * @var \Drupal\Core\Config\StorageComparerInterface
  37. */
  38. protected $storageComparer;
  39. /**
  40. * The event dispatcher used to notify subscribers.
  41. *
  42. * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
  43. */
  44. protected $eventDispatcher;
  45. /**
  46. * The configuration manager.
  47. *
  48. * @var \Drupal\Core\Config\ConfigManagerInterface
  49. */
  50. protected $configManager;
  51. /**
  52. * The used lock backend instance.
  53. *
  54. * @var \Drupal\Core\Lock\LockBackendInterface
  55. */
  56. protected $lock;
  57. /**
  58. * The typed config manager.
  59. *
  60. * @var \Drupal\Core\Config\TypedConfigManager
  61. */
  62. protected $typedConfigManager;
  63. /**
  64. * List of changes processed by the import().
  65. *
  66. * @var array
  67. */
  68. protected $processed;
  69. /**
  70. * Indicates changes to import have been validated.
  71. *
  72. * @var bool
  73. */
  74. protected $validated;
  75. /**
  76. * Constructs a configuration import object.
  77. *
  78. * @param \Drupal\Core\Config\StorageComparerInterface $storage_comparer
  79. * A storage comparer object used to determin configuration changes and
  80. * access the source and target storage objects.
  81. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
  82. * The event dispatcher used to notify subscribers of config import events.
  83. * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
  84. * The configuration manager.
  85. * @param \Drupal\Core\Lock\LockBackendInterface
  86. * The lock backend to ensure multiple imports do not occur at the same time.
  87. * @param \Drupal\Core\Config\TypedConfigManager $typed_config
  88. * The typed configuration manager.
  89. */
  90. public function __construct(StorageComparerInterface $storage_comparer, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, LockBackendInterface $lock, TypedConfigManager $typed_config) {
  91. $this->storageComparer = $storage_comparer;
  92. $this->eventDispatcher = $event_dispatcher;
  93. $this->configManager = $config_manager;
  94. $this->lock = $lock;
  95. $this->typedConfigManager = $typed_config;
  96. $this->processed = $this->storageComparer->getEmptyChangelist();
  97. }
  98. /**
  99. * Gets the configuration storage comparer.
  100. *
  101. * @return \Drupal\Core\Config\StorageComparerInterface
  102. * Storage comparer object used to calculate configuration changes.
  103. */
  104. public function getStorageComparer() {
  105. return $this->storageComparer;
  106. }
  107. /**
  108. * Resets the storage comparer and processed list.
  109. *
  110. * @return \Drupal\Core\Config\ConfigImporter
  111. * The ConfigImporter instance.
  112. */
  113. public function reset() {
  114. $this->storageComparer->reset();
  115. $this->processed = $this->storageComparer->getEmptyChangelist();
  116. $this->validated = FALSE;
  117. return $this;
  118. }
  119. /**
  120. * Checks if there are any unprocessed changes.
  121. *
  122. * @param array $ops
  123. * The operations to check for changes. Defaults to all operations, i.e.
  124. * array('delete', 'create', 'update').
  125. *
  126. * @return bool
  127. * TRUE if there are changes to process and FALSE if not.
  128. */
  129. public function hasUnprocessedChanges($ops = array('delete', 'create', 'update')) {
  130. foreach ($ops as $op) {
  131. if (count($this->getUnprocessed($op))) {
  132. return TRUE;
  133. }
  134. }
  135. return FALSE;
  136. }
  137. /**
  138. * Gets list of processed changes.
  139. *
  140. * @return array
  141. * An array containing a list of processed changes.
  142. */
  143. public function getProcessed() {
  144. return $this->processed;
  145. }
  146. /**
  147. * Sets a change as processed.
  148. *
  149. * @param string $op
  150. * The change operation performed, either delete, create or update.
  151. * @param string $name
  152. * The name of the configuration processed.
  153. */
  154. protected function setProcessed($op, $name) {
  155. $this->processed[$op][] = $name;
  156. }
  157. /**
  158. * Gets a list of unprocessed changes for a given operation.
  159. *
  160. * @param string $op
  161. * The change operation to get the unprocessed list for, either delete,
  162. * create or update.
  163. *
  164. * @return array
  165. * An array of configuration names.
  166. */
  167. public function getUnprocessed($op) {
  168. return array_diff($this->storageComparer->getChangelist($op), $this->processed[$op]);
  169. }
  170. /**
  171. * Imports the changelist to the target storage.
  172. *
  173. * @throws \Drupal\Core\Config\ConfigException
  174. *
  175. * @return \Drupal\Core\Config\ConfigImporter
  176. * The ConfigImporter instance.
  177. */
  178. public function import() {
  179. if ($this->hasUnprocessedChanges()) {
  180. // Ensure that the changes have been validated.
  181. $this->validate();
  182. if (!$this->lock->acquire(static::ID)) {
  183. // Another process is synchronizing configuration.
  184. throw new ConfigImporterException(sprintf('%s is already importing', static::ID));
  185. }
  186. $this->importInvokeOwner();
  187. $this->importConfig();
  188. // Allow modules to react to a import.
  189. $this->notify('import');
  190. // The import is now complete.
  191. $this->lock->release(static::ID);
  192. $this->reset();
  193. }
  194. return $this;
  195. }
  196. /**
  197. * Dispatches validate event for a ConfigImporter object.
  198. *
  199. * Events should throw a \Drupal\Core\Config\ConfigImporterException to
  200. * prevent an import from occurring.
  201. */
  202. public function validate() {
  203. if (!$this->validated) {
  204. if (!$this->storageComparer->validateSiteUuid()) {
  205. throw new ConfigImporterException('Site UUID in source storage does not match the target storage.');
  206. }
  207. $this->notify('validate');
  208. $this->validated = TRUE;
  209. }
  210. return $this;
  211. }
  212. /**
  213. * Writes an array of config changes from the source to the target storage.
  214. */
  215. protected function importConfig() {
  216. foreach (array('delete', 'create', 'update') as $op) {
  217. foreach ($this->getUnprocessed($op) as $name) {
  218. $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
  219. if ($op == 'delete') {
  220. $config->delete();
  221. }
  222. else {
  223. $data = $this->storageComparer->getSourceStorage()->read($name);
  224. $config->setData($data ? $data : array());
  225. $config->save();
  226. }
  227. $this->setProcessed($op, $name);
  228. }
  229. }
  230. }
  231. /**
  232. * Invokes import* methods on configuration entity storage controllers.
  233. *
  234. * Allow modules to take over configuration change operations for higher-level
  235. * configuration data.
  236. *
  237. * @todo Add support for other extension types; e.g., themes etc.
  238. */
  239. protected function importInvokeOwner() {
  240. // First pass deleted, then new, and lastly changed configuration, in order
  241. // to handle dependencies correctly.
  242. foreach (array('delete', 'create', 'update') as $op) {
  243. foreach ($this->getUnprocessed($op) as $name) {
  244. // Call to the configuration entity's storage controller to handle the
  245. // configuration change.
  246. $handled_by_module = FALSE;
  247. // Validate the configuration object name before importing it.
  248. // Config::validateName($name);
  249. if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) {
  250. $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
  251. if ($old_data = $this->storageComparer->getTargetStorage()->read($name)) {
  252. $old_config->initWithData($old_data);
  253. }
  254. $data = $this->storageComparer->getSourceStorage()->read($name);
  255. $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
  256. if ($data !== FALSE) {
  257. $new_config->setData($data);
  258. }
  259. $method = 'import' . ucfirst($op);
  260. $handled_by_module = $this->configManager->getEntityManager()->getStorageController($entity_type)->$method($name, $new_config, $old_config);
  261. }
  262. if (!empty($handled_by_module)) {
  263. $this->setProcessed($op, $name);
  264. }
  265. }
  266. }
  267. }
  268. /**
  269. * Dispatches a config importer event.
  270. *
  271. * @param string $event_name
  272. * The name of the config importer event to dispatch.
  273. */
  274. protected function notify($event_name) {
  275. $this->eventDispatcher->dispatch(static::ID . '.' . $event_name, new ConfigImporterEvent($this));
  276. }
  277. /**
  278. * Determines if a import is already running.
  279. *
  280. * @return bool
  281. * TRUE if an import is already running, FALSE if not.
  282. */
  283. public function alreadyImporting() {
  284. return !$this->lock->lockMayBeAvailable(static::ID);
  285. }
  286. /**
  287. * Returns the identifier for events and locks.
  288. *
  289. * @return string
  290. * The identifier for events and locks.
  291. */
  292. public function getId() {
  293. return static::ID;
  294. }
  295. }