FeaturesInstallStorage.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <?php
  2. namespace Drupal\features;
  3. use Drupal\Core\Site\Settings;
  4. use Drupal\Core\Config\ExtensionInstallStorage;
  5. use Drupal\Core\Config\StorageInterface;
  6. use Drupal\Core\Extension\ExtensionDiscovery;
  7. /**
  8. * Storage to access configuration and schema in installed extensions.
  9. *
  10. * Overrides the normal ExtensionInstallStorage to prevent profile from
  11. * overriding.
  12. *
  13. * Also supports modules that are not installed yet.
  14. *
  15. * @see \Drupal\Core\Config\ExtensionInstallStorage
  16. */
  17. class FeaturesInstallStorage extends ExtensionInstallStorage {
  18. /**
  19. * Overrides \Drupal\Core\Config\ExtensionInstallStorage::__construct().
  20. *
  21. * Sets includeProfile to FALSE.
  22. *
  23. * @param \Drupal\Core\Config\StorageInterface $config_storage
  24. * The active configuration store where the list of installed modules and
  25. * themes is stored.
  26. * @param string $directory
  27. * The directory to scan in each extension to scan for files. Defaults to
  28. * 'config/install'.
  29. * @param string $collection
  30. * (optional) The collection to store configuration in. Defaults to the
  31. * default collection.
  32. */
  33. public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
  34. parent::__construct($config_storage, $directory, $collection, FALSE);
  35. }
  36. /**
  37. * Returns a map of all config object names and their folders.
  38. *
  39. * The list is based on installed modules and themes. The active
  40. * configuration storage is used rather than
  41. * \Drupal\Core\Extension\ModuleHandler and
  42. * \Drupal\Core\Extension\ThemeHandler in order to resolve circular
  43. * dependencies between these services and
  44. * \Drupal\Core\Config\ConfigInstaller and
  45. * \Drupal\Core\Config\TypedConfigManager.
  46. *
  47. * NOTE: This code is copied from ExtensionInstallStorage::getAllFolders() with
  48. * the following changes (Notes in CHANGED below)
  49. * - Load all modules whether installed or not
  50. *
  51. * @return array
  52. * An array mapping config object names with directories.
  53. */
  54. public function getAllFolders() {
  55. if (!isset($this->folders)) {
  56. $this->folders = array();
  57. $this->folders += $this->getCoreNames();
  58. $install_profile = Settings::get('install_profile');
  59. $profile = drupal_get_profile();
  60. $extensions = $this->configStorage->read('core.extension');
  61. // @todo Remove this scan as part of https://www.drupal.org/node/2186491
  62. $listing = new ExtensionDiscovery(\Drupal::root());
  63. // CHANGED START: Add profile directories for any bundles that use a profile.
  64. $profile_directories = [];
  65. if ($profile) {
  66. $profile_directories[] = drupal_get_path('profile', $profile);
  67. }
  68. if ($this->includeProfile) {
  69. // Add any profiles used in bundles.
  70. /** @var \Drupal\features\FeaturesAssignerInterface $assigner */
  71. $assigner = \Drupal::service('features_assigner');
  72. $bundles = $assigner->getBundleList();
  73. foreach ($bundles as $bundle_name => $bundle) {
  74. if ($bundle->isProfile()) {
  75. // Register the profile directory.
  76. $profile_directory = 'profiles/' . $bundle->getProfileName();
  77. if (is_dir($profile_directory)) {
  78. $profile_directories[] = $profile_directory;
  79. }
  80. }
  81. }
  82. }
  83. $listing->setProfileDirectories($profile_directories);
  84. // CHANGED END
  85. if (!empty($extensions['module'])) {
  86. // CHANGED START: Find ANY modules, not just installed ones.
  87. //$modules = $extensions['module'];
  88. $module_list_scan = $listing->scan('module');
  89. $modules = $module_list_scan;
  90. // CHANGED END
  91. // Remove the install profile as this is handled later.
  92. unset($modules[$install_profile]);
  93. $profile_list = $listing->scan('profile');
  94. if ($profile && isset($profile_list[$profile])) {
  95. // Prime the drupal_get_filename() static cache with the profile info
  96. // file location so we can use drupal_get_path() on the active profile
  97. // during the module scan.
  98. // @todo Remove as part of https://www.drupal.org/node/2186491
  99. drupal_get_filename('profile', $profile, $profile_list[$profile]->getPathname());
  100. }
  101. // CHANGED START: Put Features modules first in list returned.
  102. // to allow features to override config provided by other extensions.
  103. $featuresManager = \Drupal::service('features.manager');
  104. $features_list = array();
  105. $module_list = array();
  106. foreach (array_keys($module_list_scan) as $module) {
  107. if ($featuresManager->isFeatureModule($module_list_scan[$module])) {
  108. $features_list[$module] = $module_list_scan[$module];
  109. }
  110. else {
  111. $module_list[$module] = $module_list_scan[$module];
  112. }
  113. }
  114. $this->folders += $this->getComponentNames($features_list);
  115. $this->folders += $this->getComponentNames($module_list);
  116. // CHANGED END
  117. }
  118. if (!empty($extensions['theme'])) {
  119. $theme_list_scan = $listing->scan('theme');
  120. foreach (array_keys($extensions['theme']) as $theme) {
  121. if (isset($theme_list_scan[$theme])) {
  122. $theme_list[$theme] = $theme_list_scan[$theme];
  123. }
  124. }
  125. $this->folders += $this->getComponentNames($theme_list);
  126. }
  127. if ($this->includeProfile) {
  128. // The install profile can override module default configuration. We do
  129. // this by replacing the config file path from the module/theme with the
  130. // install profile version if there are any duplicates.
  131. if (isset($profile)) {
  132. if (!isset($profile_list)) {
  133. $profile_list = $listing->scan('profile');
  134. }
  135. if (isset($profile_list[$profile])) {
  136. $profile_folders = $this->getComponentNames(array($profile_list[$profile]));
  137. $this->folders = $profile_folders + $this->folders;
  138. }
  139. }
  140. }
  141. }
  142. return $this->folders;
  143. }
  144. }