3 namespace Drupal\Core\Config;
5 use Drupal\Core\Extension\ExtensionDiscovery;
6 use Drupal\Core\Extension\Extension;
9 * Storage used by the Drupal installer.
11 * This storage performs a full filesystem scan to discover all available
12 * extensions and reads from all default config directories that exist.
14 * This special implementation MUST NOT be used anywhere else than the early
15 * installer environment.
17 * @see \Drupal\Core\DependencyInjection\InstallServiceProvider
19 class InstallStorage extends FileStorage {
22 * Extension sub-directory containing default configuration for installation.
24 const CONFIG_INSTALL_DIRECTORY = 'config/install';
27 * Extension sub-directory containing optional configuration for installation.
29 const CONFIG_OPTIONAL_DIRECTORY = 'config/optional';
32 * Extension sub-directory containing configuration schema.
34 const CONFIG_SCHEMA_DIRECTORY = 'config/schema';
37 * Folder map indexed by configuration name.
44 * The directory to scan in each extension to scan for files.
51 * Constructs an InstallStorage object.
53 * @param string $directory
54 * The directory to scan in each extension to scan for files. Defaults to
56 * @param string $collection
57 * (optional) The collection to store configuration in. Defaults to the
60 public function __construct($directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
61 parent::__construct($directory, $collection);
65 * Overrides Drupal\Core\Config\FileStorage::getFilePath().
67 * Returns the path to the configuration file.
69 * Determines the owner and path to the default configuration file of a
70 * requested config object name located in the installation profile, a module,
71 * or a theme (in this order).
74 * The path to the configuration file.
76 * @todo Improve this when figuring out how we want to handle configuration in
77 * installation profiles. For instance, a config object actually has to be
78 * searched in the profile first (whereas the profile is never the owner);
79 * only afterwards check for a corresponding module or theme.
81 public function getFilePath($name) {
82 $folders = $this->getAllFolders();
83 if (isset($folders[$name])) {
84 return $folders[$name] . '/' . $name . '.' . $this->getFileExtension();
86 // If any code in the early installer requests a configuration object that
87 // does not exist anywhere as default config, then that must be mistake.
88 throw new StorageException("Missing configuration file: $name");
94 public function exists($name) {
95 return array_key_exists($name, $this->getAllFolders());
99 * Overrides Drupal\Core\Config\FileStorage::write().
101 * @throws \Drupal\Core\Config\StorageException
103 public function write($name, array $data) {
104 throw new StorageException('Write operation is not allowed.');
108 * Overrides Drupal\Core\Config\FileStorage::delete().
110 * @throws \Drupal\Core\Config\StorageException
112 public function delete($name) {
113 throw new StorageException('Delete operation is not allowed.');
117 * Overrides Drupal\Core\Config\FileStorage::rename().
119 * @throws \Drupal\Core\Config\StorageException
121 public function rename($name, $new_name) {
122 throw new StorageException('Rename operation is not allowed.');
128 public function listAll($prefix = '') {
129 $names = array_keys($this->getAllFolders());
135 foreach ($names as $index => $name) {
136 if (strpos($name, $prefix) === 0) {
137 $return[$index] = $names[$index];
145 * Returns a map of all config object names and their folders.
148 * An array mapping config object names with directories.
150 protected function getAllFolders() {
151 if (!isset($this->folders)) {
153 $this->folders += $this->getCoreNames();
154 // Perform an ExtensionDiscovery scan as we cannot use drupal_get_path()
155 // yet because the system module may not yet be enabled during install.
156 // @todo Remove as part of https://www.drupal.org/node/2186491
157 $listing = new ExtensionDiscovery(\Drupal::root());
158 if ($profile = drupal_get_profile()) {
159 $profile_list = $listing->scan('profile');
160 if (isset($profile_list[$profile])) {
161 // Prime the drupal_get_filename() static cache with the profile info
162 // file location so we can use drupal_get_path() on the active profile
163 // during the module scan.
164 // @todo Remove as part of https://www.drupal.org/node/2186491
165 drupal_get_filename('profile', $profile, $profile_list[$profile]->getPathname());
166 $this->folders += $this->getComponentNames([$profile_list[$profile]]);
169 // @todo Remove as part of https://www.drupal.org/node/2186491
170 $this->folders += $this->getComponentNames($listing->scan('module'));
171 $this->folders += $this->getComponentNames($listing->scan('theme'));
173 return $this->folders;
177 * Get all configuration names and folders for a list of modules or themes.
179 * @param \Drupal\Core\Extension\Extension[] $list
180 * An associative array of Extension objects, keyed by extension name.
183 * Folders indexed by configuration name.
185 public function getComponentNames(array $list) {
186 $extension = '.' . $this->getFileExtension();
187 $pattern = '/' . preg_quote($extension, '/') . '$/';
189 foreach ($list as $extension_object) {
190 // We don't have to use ExtensionDiscovery here because our list of
191 // extensions was already obtained through an ExtensionDiscovery scan.
192 $directory = $this->getComponentFolder($extension_object);
193 if (is_dir($directory)) {
194 // glob() directly calls into libc glob(), which is not aware of PHP
195 // stream wrappers. Same for \GlobIterator (which additionally requires
196 // an absolute realpath() on Windows).
197 // @see https://github.com/mikey179/vfsStream/issues/2
198 $files = scandir($directory);
200 foreach ($files as $file) {
201 if ($file[0] !== '.' && preg_match($pattern, $file)) {
202 $folders[basename($file, $extension)] = $directory;
211 * Get all configuration names and folders for Drupal core.
214 * Folders indexed by configuration name.
216 public function getCoreNames() {
217 $extension = '.' . $this->getFileExtension();
218 $pattern = '/' . preg_quote($extension, '/') . '$/';
220 $directory = $this->getCoreFolder();
221 if (is_dir($directory)) {
222 // glob() directly calls into libc glob(), which is not aware of PHP
223 // stream wrappers. Same for \GlobIterator (which additionally requires an
224 // absolute realpath() on Windows).
225 // @see https://github.com/mikey179/vfsStream/issues/2
226 $files = scandir($directory);
228 foreach ($files as $file) {
229 if ($file[0] !== '.' && preg_match($pattern, $file)) {
230 $folders[basename($file, $extension)] = $directory;
238 * Get folder inside each component that contains the files.
240 * @param \Drupal\Core\Extension\Extension $extension
241 * The Extension object for the component.
244 * The configuration folder name for this component.
246 protected function getComponentFolder(Extension $extension) {
247 return $extension->getPath() . '/' . $this->getCollectionDirectory();
251 * Get folder inside Drupal core that contains the files.
254 * The configuration folder name for core.
256 protected function getCoreFolder() {
257 return drupal_get_path('core', 'core') . '/' . $this->getCollectionDirectory();
261 * Overrides Drupal\Core\Config\FileStorage::deleteAll().
263 * @throws \Drupal\Core\Config\StorageException
265 public function deleteAll($prefix = '') {
266 throw new StorageException('Delete operation is not allowed.');
270 * Resets the static cache.
272 public function reset() {
273 $this->folders = NULL;