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
|
<?php
/**
* @file
* API for loading and interacting with Drupal modules.
*/
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 \Drupal\Core\Extension\ThemeHandler::listInfo()
*/
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 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');
}
/**
* 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;
}
/**
* Returns an array of modules required by core.
*/
function drupal_required_modules() {
$listing = new ExtensionDiscovery(\Drupal::root());
$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) {
$extension_config = \Drupal::configFactory()->getEditable('core.extension');
if ($extension_config->get("module.$module") !== NULL) {
// Pre-cast the $weight to an integer so that we can save this without using
// schema. This is a performance improvement for module installation.
$extension_config
->set("module.$module", (int) $weight)
->set('module', module_config_sort($extension_config->get('module')))
->save(TRUE);
// Prepare the new module list, sorted by weight, including filenames.
// @see \Drupal\Core\Extension\ModuleInstaller::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;
}
|