1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
<?php
/**
* @file
* API for loading and interacting with Drupal modules.
*/
use Drupal\Core\Cache\Cache;
use Drupal\Core\Extension\ExtensionDiscovery;
/**
* Builds a list of installed themes.
*
* @param $type
* The type of list to return:
* - theme: All installed themes.
*
* @return
* An associative array of themes, keyed by name.
* For $type 'theme', the array values are objects representing the
* respective database row, with the 'info' property already unserialized.
*
* @see list_themes()
*/
function system_list($type) {
$lists = &drupal_static(__FUNCTION__);
if ($cached = \Drupal::cache('bootstrap')->get('system_list')) {
$lists = $cached->data;
}
else {
$lists = array(
'theme' => array(),
'filepaths' => array(),
);
// ThemeHandler maintains the 'system.theme.data' state record.
$theme_data = \Drupal::state()->get('system.theme.data', array());
foreach ($theme_data as $name => $theme) {
$lists['theme'][$name] = $theme;
$lists['filepaths'][] = array(
'type' => 'theme',
'name' => $name,
'filepath' => $theme->getPathname(),
);
}
\Drupal::cache('bootstrap')->set('system_list', $lists);
}
// To avoid a separate database lookup for the filepath, prime the
// drupal_get_filename() static cache with all enabled modules and themes.
foreach ($lists['filepaths'] as $item) {
system_register($item['type'], $item['name'], $item['filepath']);
}
return $lists[$type];
}
/**
* Resets all system_list() caches.
*/
function system_list_reset() {
drupal_static_reset('system_list');
drupal_static_reset('system_rebuild_module_data');
\Drupal::cache('bootstrap')->delete('system_list');
// Clear the library info cache.
// Libraries may be provided by all extension types, and may be altered by any
// other extensions (types) due to the nature of
// \Drupal\Core\Extension\ModuleHandler::alter() and the fact that profiles
// are recorded and handled as modules.
// @todo Trigger an event upon module install/uninstall and theme
// enable/disable, and move this into an event subscriber.
// @see https://drupal.org/node/2206347
Cache::invalidateTags(array('extension'));
}
/**
* Registers an extension in runtime registries for execution.
*
* @param string $type
* The extension type; e.g., 'module' or 'theme'.
* @param string $name
* The internal name of the extension; e.g., 'node'.
* @param string $uri
* The relative URI of the primary extension file; e.g.,
* 'core/modules/node/node.module'.
*/
function system_register($type, $name, $uri) {
drupal_get_filename($type, $name, $uri);
drupal_classloader_register($name, dirname($uri));
}
/**
* Loads a module's installation hooks.
*
* @param $module
* The name of the module (without the .module extension).
*
* @return
* The name of the module's install file, if successful; FALSE otherwise.
*/
function module_load_install($module) {
// Make sure the installation API is available
include_once __DIR__ . '/install.inc';
return module_load_include('install', $module);
}
/**
* Loads a module include file.
*
* Examples:
* @code
* // Load node.admin.inc from the node module.
* module_load_include('inc', 'node', 'node.admin');
* // Load content_types.inc from the node module.
* module_load_include('inc', 'node', 'content_types');
* @endcode
*
* Do not use this function to load an install file, use module_load_install()
* instead. Do not use this function in a global context since it requires
* Drupal to be fully bootstrapped, use require_once DRUPAL_ROOT . '/path/file'
* instead.
*
* @param $type
* The include file's type (file extension).
* @param $module
* The module to which the include file belongs.
* @param $name
* (optional) The base file name (without the $type extension). If omitted,
* $module is used; i.e., resulting in "$module.$type" by default.
*
* @return
* The name of the included file, if successful; FALSE otherwise.
*
* @todo The module_handler service has a loadInclude() method which performs
* this same task but only for enabled modules. Figure out a way to move this
* functionality entirely into the module_handler while keeping the ability to
* load the files of disabled modules.
*/
function module_load_include($type, $module, $name = NULL) {
if (!isset($name)) {
$name = $module;
}
if (function_exists('drupal_get_path')) {
$file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
if (is_file($file)) {
require_once $file;
return $file;
}
}
return FALSE;
}
/**
* Installs a given list of modules.
*
* @see \Drupal\Core\Extension\ModuleHandlerInterface::install()
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. Use
* \Drupal::moduleHandler()->install($module_list, $enable_dependencies = TRUE).
*/
function module_install($module_list, $enable_dependencies = TRUE) {
return \Drupal::moduleHandler()->install($module_list, $enable_dependencies);
}
/**
* Installs a given list of modules.
*
* @see \Drupal\Core\Extension\ModuleHandlerInterface::module_install()
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. Use
* \Drupal::moduleHandler()->uninstall($module_list, $enable_dependencies = TRUE).
*/
function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) {
return \Drupal::moduleHandler()->uninstall($module_list, $uninstall_dependents);
}
/**
* Returns an array of modules required by core.
*/
function drupal_required_modules() {
$listing = new ExtensionDiscovery();
$files = $listing->scan('module');
$required = array();
// Unless called by the installer, an installation profile is required and
// must always be loaded. drupal_get_profile() also returns the installation
// profile in the installer, but only after it has been selected.
if ($profile = drupal_get_profile()) {
$required[] = $profile;
}
foreach ($files as $name => $file) {
$info = \Drupal::service('info_parser')->parse($file->getPathname());
if (!empty($info) && !empty($info['required']) && $info['required']) {
$required[] = $name;
}
}
return $required;
}
/**
* Sets weight of a particular module.
*
* The weight of uninstalled modules cannot be changed.
*
* @param string $module
* The name of the module (without the .module extension).
* @param int $weight
* An integer representing the weight of the module.
*/
function module_set_weight($module, $weight) {
// Update the module weight in the config file that contains it.
$extension_config = \Drupal::config('core.extension');
if ($extension_config->get("module.$module") !== NULL) {
$extension_config
->set("module.$module", $weight)
->set('module', module_config_sort($extension_config->get('module')))
->save();
// Prepare the new module list, sorted by weight, including filenames.
// @see \Drupal\Core\Extension\ModuleHandler::install()
$module_handler = \Drupal::moduleHandler();
$current_module_filenames = $module_handler->getModuleList();
$current_modules = array_fill_keys(array_keys($current_module_filenames), 0);
$current_modules = module_config_sort(array_merge($current_modules, $extension_config->get('module')));
$module_filenames = array();
foreach ($current_modules as $name => $weight) {
$module_filenames[$name] = $current_module_filenames[$name];
}
// Update the module list in the extension handler.
$module_handler->setModuleList($module_filenames);
return;
}
}
/**
* Sorts the configured list of enabled modules.
*
* The list of enabled modules is expected to be ordered by weight and name.
* The list is always sorted on write to avoid the overhead on read.
*
* @param array $data
* An array of module configuration data.
*
* @return array
* An array of module configuration data sorted by weight and name.
*/
function module_config_sort($data) {
// PHP array sorting functions such as uasort() do not work with both keys and
// values at the same time, so we achieve weight and name sorting by computing
// strings with both information concatenated (weight first, name second) and
// use that as a regular string sort reference list via array_multisort(),
// compound of "[sign-as-integer][padded-integer-weight][name]"; e.g., given
// two modules and weights (spaces added for clarity):
// - Block with weight -5: 0 0000000000000000005 block
// - Node with weight 0: 1 0000000000000000000 node
$sort = array();
foreach ($data as $name => $weight) {
// Prefix negative weights with 0, positive weights with 1.
// +/- signs cannot be used, since + (ASCII 43) is before - (ASCII 45).
$prefix = (int) ($weight >= 0);
// The maximum weight is PHP_INT_MAX, so pad all weights to 19 digits.
$sort[] = $prefix . sprintf('%019d', abs($weight)) . $name;
}
array_multisort($sort, SORT_STRING, $data);
return $data;
}
|