danielebarchiesi@0
|
1 <?php
|
danielebarchiesi@0
|
2
|
danielebarchiesi@0
|
3 /**
|
danielebarchiesi@0
|
4 * @file
|
danielebarchiesi@0
|
5 * API for loading and interacting with Drupal modules.
|
danielebarchiesi@0
|
6 */
|
danielebarchiesi@0
|
7
|
danielebarchiesi@0
|
8 /**
|
danielebarchiesi@0
|
9 * Loads all the modules that have been enabled in the system table.
|
danielebarchiesi@0
|
10 *
|
danielebarchiesi@0
|
11 * @param $bootstrap
|
danielebarchiesi@0
|
12 * Whether to load only the reduced set of modules loaded in "bootstrap mode"
|
danielebarchiesi@0
|
13 * for cached pages. See bootstrap.inc.
|
danielebarchiesi@0
|
14 *
|
danielebarchiesi@0
|
15 * @return
|
danielebarchiesi@0
|
16 * If $bootstrap is NULL, return a boolean indicating whether all modules
|
danielebarchiesi@0
|
17 * have been loaded.
|
danielebarchiesi@0
|
18 */
|
danielebarchiesi@0
|
19 function module_load_all($bootstrap = FALSE) {
|
danielebarchiesi@0
|
20 static $has_run = FALSE;
|
danielebarchiesi@0
|
21
|
danielebarchiesi@0
|
22 if (isset($bootstrap)) {
|
danielebarchiesi@0
|
23 foreach (module_list(TRUE, $bootstrap) as $module) {
|
danielebarchiesi@0
|
24 drupal_load('module', $module);
|
danielebarchiesi@0
|
25 }
|
danielebarchiesi@0
|
26 // $has_run will be TRUE if $bootstrap is FALSE.
|
danielebarchiesi@0
|
27 $has_run = !$bootstrap;
|
danielebarchiesi@0
|
28 }
|
danielebarchiesi@0
|
29 return $has_run;
|
danielebarchiesi@0
|
30 }
|
danielebarchiesi@0
|
31
|
danielebarchiesi@0
|
32
|
danielebarchiesi@0
|
33 /**
|
danielebarchiesi@0
|
34 * Returns a list of currently active modules.
|
danielebarchiesi@0
|
35 *
|
danielebarchiesi@0
|
36 * Usually, this returns a list of all enabled modules. When called early on in
|
danielebarchiesi@0
|
37 * the bootstrap, it will return a list of vital modules only (those needed to
|
danielebarchiesi@0
|
38 * generate cached pages).
|
danielebarchiesi@0
|
39 *
|
danielebarchiesi@0
|
40 * All parameters to this function are optional and should generally not be
|
danielebarchiesi@0
|
41 * changed from their defaults.
|
danielebarchiesi@0
|
42 *
|
danielebarchiesi@0
|
43 * @param $refresh
|
danielebarchiesi@0
|
44 * (optional) Whether to force the module list to be regenerated (such as
|
danielebarchiesi@0
|
45 * after the administrator has changed the system settings). Defaults to
|
danielebarchiesi@0
|
46 * FALSE.
|
danielebarchiesi@0
|
47 * @param $bootstrap_refresh
|
danielebarchiesi@0
|
48 * (optional) When $refresh is TRUE, setting $bootstrap_refresh to TRUE forces
|
danielebarchiesi@0
|
49 * the module list to be regenerated using the reduced set of modules loaded
|
danielebarchiesi@0
|
50 * in "bootstrap mode" for cached pages. Otherwise, setting $refresh to TRUE
|
danielebarchiesi@0
|
51 * generates the complete list of enabled modules.
|
danielebarchiesi@0
|
52 * @param $sort
|
danielebarchiesi@0
|
53 * (optional) By default, modules are ordered by weight and module name. Set
|
danielebarchiesi@0
|
54 * this option to TRUE to return a module list ordered only by module name.
|
danielebarchiesi@0
|
55 * @param $fixed_list
|
danielebarchiesi@0
|
56 * (optional) If an array of module names is provided, this will override the
|
danielebarchiesi@0
|
57 * module list with the given set of modules. This will persist until the next
|
danielebarchiesi@0
|
58 * call with $refresh set to TRUE or with a new $fixed_list passed in. This
|
danielebarchiesi@0
|
59 * parameter is primarily intended for internal use (e.g., in install.php and
|
danielebarchiesi@0
|
60 * update.php).
|
danielebarchiesi@0
|
61 *
|
danielebarchiesi@0
|
62 * @return
|
danielebarchiesi@0
|
63 * An associative array whose keys and values are the names of the modules in
|
danielebarchiesi@0
|
64 * the list.
|
danielebarchiesi@0
|
65 */
|
danielebarchiesi@0
|
66 function module_list($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE, $fixed_list = NULL) {
|
danielebarchiesi@0
|
67 static $list = array(), $sorted_list;
|
danielebarchiesi@0
|
68
|
danielebarchiesi@0
|
69 if (empty($list) || $refresh || $fixed_list) {
|
danielebarchiesi@0
|
70 $list = array();
|
danielebarchiesi@0
|
71 $sorted_list = NULL;
|
danielebarchiesi@0
|
72 if ($fixed_list) {
|
danielebarchiesi@0
|
73 foreach ($fixed_list as $name => $module) {
|
danielebarchiesi@0
|
74 drupal_get_filename('module', $name, $module['filename']);
|
danielebarchiesi@0
|
75 $list[$name] = $name;
|
danielebarchiesi@0
|
76 }
|
danielebarchiesi@0
|
77 }
|
danielebarchiesi@0
|
78 else {
|
danielebarchiesi@0
|
79 if ($refresh) {
|
danielebarchiesi@0
|
80 // For the $refresh case, make sure that system_list() returns fresh
|
danielebarchiesi@0
|
81 // data.
|
danielebarchiesi@0
|
82 drupal_static_reset('system_list');
|
danielebarchiesi@0
|
83 }
|
danielebarchiesi@0
|
84 if ($bootstrap_refresh) {
|
danielebarchiesi@0
|
85 $list = system_list('bootstrap');
|
danielebarchiesi@0
|
86 }
|
danielebarchiesi@0
|
87 else {
|
danielebarchiesi@0
|
88 // Not using drupal_map_assoc() here as that requires common.inc.
|
danielebarchiesi@0
|
89 $list = array_keys(system_list('module_enabled'));
|
danielebarchiesi@0
|
90 $list = (!empty($list) ? array_combine($list, $list) : array());
|
danielebarchiesi@0
|
91 }
|
danielebarchiesi@0
|
92 }
|
danielebarchiesi@0
|
93 }
|
danielebarchiesi@0
|
94 if ($sort) {
|
danielebarchiesi@0
|
95 if (!isset($sorted_list)) {
|
danielebarchiesi@0
|
96 $sorted_list = $list;
|
danielebarchiesi@0
|
97 ksort($sorted_list);
|
danielebarchiesi@0
|
98 }
|
danielebarchiesi@0
|
99 return $sorted_list;
|
danielebarchiesi@0
|
100 }
|
danielebarchiesi@0
|
101 return $list;
|
danielebarchiesi@0
|
102 }
|
danielebarchiesi@0
|
103
|
danielebarchiesi@0
|
104 /**
|
danielebarchiesi@0
|
105 * Builds a list of bootstrap modules and enabled modules and themes.
|
danielebarchiesi@0
|
106 *
|
danielebarchiesi@0
|
107 * @param $type
|
danielebarchiesi@0
|
108 * The type of list to return:
|
danielebarchiesi@0
|
109 * - module_enabled: All enabled modules.
|
danielebarchiesi@0
|
110 * - bootstrap: All enabled modules required for bootstrap.
|
danielebarchiesi@0
|
111 * - theme: All themes.
|
danielebarchiesi@0
|
112 *
|
danielebarchiesi@0
|
113 * @return
|
danielebarchiesi@0
|
114 * An associative array of modules or themes, keyed by name. For $type
|
danielebarchiesi@0
|
115 * 'bootstrap', the array values equal the keys. For $type 'module_enabled'
|
danielebarchiesi@0
|
116 * or 'theme', the array values are objects representing the respective
|
danielebarchiesi@0
|
117 * database row, with the 'info' property already unserialized.
|
danielebarchiesi@0
|
118 *
|
danielebarchiesi@0
|
119 * @see module_list()
|
danielebarchiesi@0
|
120 * @see list_themes()
|
danielebarchiesi@0
|
121 */
|
danielebarchiesi@0
|
122 function system_list($type) {
|
danielebarchiesi@0
|
123 $lists = &drupal_static(__FUNCTION__);
|
danielebarchiesi@0
|
124
|
danielebarchiesi@0
|
125 // For bootstrap modules, attempt to fetch the list from cache if possible.
|
danielebarchiesi@0
|
126 // if not fetch only the required information to fire bootstrap hooks
|
danielebarchiesi@0
|
127 // in case we are going to serve the page from cache.
|
danielebarchiesi@0
|
128 if ($type == 'bootstrap') {
|
danielebarchiesi@0
|
129 if (isset($lists['bootstrap'])) {
|
danielebarchiesi@0
|
130 return $lists['bootstrap'];
|
danielebarchiesi@0
|
131 }
|
danielebarchiesi@0
|
132 if ($cached = cache_get('bootstrap_modules', 'cache_bootstrap')) {
|
danielebarchiesi@0
|
133 $bootstrap_list = $cached->data;
|
danielebarchiesi@0
|
134 }
|
danielebarchiesi@0
|
135 else {
|
danielebarchiesi@0
|
136 $bootstrap_list = db_query("SELECT name, filename FROM {system} WHERE status = 1 AND bootstrap = 1 AND type = 'module' ORDER BY weight ASC, name ASC")->fetchAllAssoc('name');
|
danielebarchiesi@0
|
137 cache_set('bootstrap_modules', $bootstrap_list, 'cache_bootstrap');
|
danielebarchiesi@0
|
138 }
|
danielebarchiesi@0
|
139 // To avoid a separate database lookup for the filepath, prime the
|
danielebarchiesi@0
|
140 // drupal_get_filename() static cache for bootstrap modules only.
|
danielebarchiesi@0
|
141 // The rest is stored separately to keep the bootstrap module cache small.
|
danielebarchiesi@0
|
142 foreach ($bootstrap_list as $module) {
|
danielebarchiesi@0
|
143 drupal_get_filename('module', $module->name, $module->filename);
|
danielebarchiesi@0
|
144 }
|
danielebarchiesi@0
|
145 // We only return the module names here since module_list() doesn't need
|
danielebarchiesi@0
|
146 // the filename itself.
|
danielebarchiesi@0
|
147 $lists['bootstrap'] = array_keys($bootstrap_list);
|
danielebarchiesi@0
|
148 }
|
danielebarchiesi@0
|
149 // Otherwise build the list for enabled modules and themes.
|
danielebarchiesi@0
|
150 elseif (!isset($lists['module_enabled'])) {
|
danielebarchiesi@0
|
151 if ($cached = cache_get('system_list', 'cache_bootstrap')) {
|
danielebarchiesi@0
|
152 $lists = $cached->data;
|
danielebarchiesi@0
|
153 }
|
danielebarchiesi@0
|
154 else {
|
danielebarchiesi@0
|
155 $lists = array(
|
danielebarchiesi@0
|
156 'module_enabled' => array(),
|
danielebarchiesi@0
|
157 'theme' => array(),
|
danielebarchiesi@0
|
158 'filepaths' => array(),
|
danielebarchiesi@0
|
159 );
|
danielebarchiesi@0
|
160 // The module name (rather than the filename) is used as the fallback
|
danielebarchiesi@0
|
161 // weighting in order to guarantee consistent behavior across different
|
danielebarchiesi@0
|
162 // Drupal installations, which might have modules installed in different
|
danielebarchiesi@0
|
163 // locations in the file system. The ordering here must also be
|
danielebarchiesi@0
|
164 // consistent with the one used in module_implements().
|
danielebarchiesi@0
|
165 $result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC");
|
danielebarchiesi@0
|
166 foreach ($result as $record) {
|
danielebarchiesi@0
|
167 $record->info = unserialize($record->info);
|
danielebarchiesi@0
|
168 // Build a list of all enabled modules.
|
danielebarchiesi@0
|
169 if ($record->type == 'module') {
|
danielebarchiesi@0
|
170 $lists['module_enabled'][$record->name] = $record;
|
danielebarchiesi@0
|
171 }
|
danielebarchiesi@0
|
172 // Build a list of themes.
|
danielebarchiesi@0
|
173 if ($record->type == 'theme') {
|
danielebarchiesi@0
|
174 $lists['theme'][$record->name] = $record;
|
danielebarchiesi@0
|
175 }
|
danielebarchiesi@0
|
176 // Build a list of filenames so drupal_get_filename can use it.
|
danielebarchiesi@0
|
177 if ($record->status) {
|
danielebarchiesi@0
|
178 $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename);
|
danielebarchiesi@0
|
179 }
|
danielebarchiesi@0
|
180 }
|
danielebarchiesi@0
|
181 foreach ($lists['theme'] as $key => $theme) {
|
danielebarchiesi@0
|
182 if (!empty($theme->info['base theme'])) {
|
danielebarchiesi@0
|
183 // Make a list of the theme's base themes.
|
danielebarchiesi@0
|
184 require_once DRUPAL_ROOT . '/includes/theme.inc';
|
danielebarchiesi@0
|
185 $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
|
danielebarchiesi@0
|
186 // Don't proceed if there was a problem with the root base theme.
|
danielebarchiesi@0
|
187 if (!current($lists['theme'][$key]->base_themes)) {
|
danielebarchiesi@0
|
188 continue;
|
danielebarchiesi@0
|
189 }
|
danielebarchiesi@0
|
190 // Determine the root base theme.
|
danielebarchiesi@0
|
191 $base_key = key($lists['theme'][$key]->base_themes);
|
danielebarchiesi@0
|
192 // Add to the list of sub-themes for each of the theme's base themes.
|
danielebarchiesi@0
|
193 foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
|
danielebarchiesi@0
|
194 $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
|
danielebarchiesi@0
|
195 }
|
danielebarchiesi@0
|
196 // Add the base theme's theme engine info.
|
danielebarchiesi@0
|
197 $lists['theme'][$key]->info['engine'] = isset($lists['theme'][$base_key]->info['engine']) ? $lists['theme'][$base_key]->info['engine'] : 'theme';
|
danielebarchiesi@0
|
198 }
|
danielebarchiesi@0
|
199 else {
|
danielebarchiesi@0
|
200 // A plain theme is its own engine.
|
danielebarchiesi@0
|
201 $base_key = $key;
|
danielebarchiesi@0
|
202 if (!isset($lists['theme'][$key]->info['engine'])) {
|
danielebarchiesi@0
|
203 $lists['theme'][$key]->info['engine'] = 'theme';
|
danielebarchiesi@0
|
204 }
|
danielebarchiesi@0
|
205 }
|
danielebarchiesi@0
|
206 // Set the theme engine prefix.
|
danielebarchiesi@0
|
207 $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
|
danielebarchiesi@0
|
208 }
|
danielebarchiesi@0
|
209 cache_set('system_list', $lists, 'cache_bootstrap');
|
danielebarchiesi@0
|
210 }
|
danielebarchiesi@0
|
211 // To avoid a separate database lookup for the filepath, prime the
|
danielebarchiesi@0
|
212 // drupal_get_filename() static cache with all enabled modules and themes.
|
danielebarchiesi@0
|
213 foreach ($lists['filepaths'] as $item) {
|
danielebarchiesi@0
|
214 drupal_get_filename($item['type'], $item['name'], $item['filepath']);
|
danielebarchiesi@0
|
215 }
|
danielebarchiesi@0
|
216 }
|
danielebarchiesi@0
|
217
|
danielebarchiesi@0
|
218 return $lists[$type];
|
danielebarchiesi@0
|
219 }
|
danielebarchiesi@0
|
220
|
danielebarchiesi@0
|
221 /**
|
danielebarchiesi@0
|
222 * Resets all system_list() caches.
|
danielebarchiesi@0
|
223 */
|
danielebarchiesi@0
|
224 function system_list_reset() {
|
danielebarchiesi@0
|
225 drupal_static_reset('system_list');
|
danielebarchiesi@0
|
226 drupal_static_reset('system_rebuild_module_data');
|
danielebarchiesi@0
|
227 drupal_static_reset('list_themes');
|
danielebarchiesi@0
|
228 cache_clear_all('bootstrap_modules', 'cache_bootstrap');
|
danielebarchiesi@0
|
229 cache_clear_all('system_list', 'cache_bootstrap');
|
danielebarchiesi@0
|
230 }
|
danielebarchiesi@0
|
231
|
danielebarchiesi@0
|
232 /**
|
danielebarchiesi@0
|
233 * Determines which modules require and are required by each module.
|
danielebarchiesi@0
|
234 *
|
danielebarchiesi@0
|
235 * @param $files
|
danielebarchiesi@0
|
236 * The array of filesystem objects used to rebuild the cache.
|
danielebarchiesi@0
|
237 *
|
danielebarchiesi@0
|
238 * @return
|
danielebarchiesi@0
|
239 * The same array with the new keys for each module:
|
danielebarchiesi@0
|
240 * - requires: An array with the keys being the modules that this module
|
danielebarchiesi@0
|
241 * requires.
|
danielebarchiesi@0
|
242 * - required_by: An array with the keys being the modules that will not work
|
danielebarchiesi@0
|
243 * without this module.
|
danielebarchiesi@0
|
244 */
|
danielebarchiesi@0
|
245 function _module_build_dependencies($files) {
|
danielebarchiesi@0
|
246 require_once DRUPAL_ROOT . '/includes/graph.inc';
|
danielebarchiesi@0
|
247 foreach ($files as $filename => $file) {
|
danielebarchiesi@0
|
248 $graph[$file->name]['edges'] = array();
|
danielebarchiesi@0
|
249 if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
|
danielebarchiesi@0
|
250 foreach ($file->info['dependencies'] as $dependency) {
|
danielebarchiesi@0
|
251 $dependency_data = drupal_parse_dependency($dependency);
|
danielebarchiesi@0
|
252 $graph[$file->name]['edges'][$dependency_data['name']] = $dependency_data;
|
danielebarchiesi@0
|
253 }
|
danielebarchiesi@0
|
254 }
|
danielebarchiesi@0
|
255 }
|
danielebarchiesi@0
|
256 drupal_depth_first_search($graph);
|
danielebarchiesi@0
|
257 foreach ($graph as $module => $data) {
|
danielebarchiesi@0
|
258 $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
|
danielebarchiesi@0
|
259 $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array();
|
danielebarchiesi@0
|
260 $files[$module]->sort = $data['weight'];
|
danielebarchiesi@0
|
261 }
|
danielebarchiesi@0
|
262 return $files;
|
danielebarchiesi@0
|
263 }
|
danielebarchiesi@0
|
264
|
danielebarchiesi@0
|
265 /**
|
danielebarchiesi@0
|
266 * Determines whether a given module exists.
|
danielebarchiesi@0
|
267 *
|
danielebarchiesi@0
|
268 * @param $module
|
danielebarchiesi@0
|
269 * The name of the module (without the .module extension).
|
danielebarchiesi@0
|
270 *
|
danielebarchiesi@0
|
271 * @return
|
danielebarchiesi@0
|
272 * TRUE if the module is both installed and enabled.
|
danielebarchiesi@0
|
273 */
|
danielebarchiesi@0
|
274 function module_exists($module) {
|
danielebarchiesi@0
|
275 $list = module_list();
|
danielebarchiesi@0
|
276 return isset($list[$module]);
|
danielebarchiesi@0
|
277 }
|
danielebarchiesi@0
|
278
|
danielebarchiesi@0
|
279 /**
|
danielebarchiesi@0
|
280 * Loads a module's installation hooks.
|
danielebarchiesi@0
|
281 *
|
danielebarchiesi@0
|
282 * @param $module
|
danielebarchiesi@0
|
283 * The name of the module (without the .module extension).
|
danielebarchiesi@0
|
284 *
|
danielebarchiesi@0
|
285 * @return
|
danielebarchiesi@0
|
286 * The name of the module's install file, if successful; FALSE otherwise.
|
danielebarchiesi@0
|
287 */
|
danielebarchiesi@0
|
288 function module_load_install($module) {
|
danielebarchiesi@0
|
289 // Make sure the installation API is available
|
danielebarchiesi@0
|
290 include_once DRUPAL_ROOT . '/includes/install.inc';
|
danielebarchiesi@0
|
291
|
danielebarchiesi@0
|
292 return module_load_include('install', $module);
|
danielebarchiesi@0
|
293 }
|
danielebarchiesi@0
|
294
|
danielebarchiesi@0
|
295 /**
|
danielebarchiesi@0
|
296 * Loads a module include file.
|
danielebarchiesi@0
|
297 *
|
danielebarchiesi@0
|
298 * Examples:
|
danielebarchiesi@0
|
299 * @code
|
danielebarchiesi@0
|
300 * // Load node.admin.inc from the node module.
|
danielebarchiesi@0
|
301 * module_load_include('inc', 'node', 'node.admin');
|
danielebarchiesi@0
|
302 * // Load content_types.inc from the node module.
|
danielebarchiesi@0
|
303 * module_load_include('inc', 'node', 'content_types');
|
danielebarchiesi@0
|
304 * @endcode
|
danielebarchiesi@0
|
305 *
|
danielebarchiesi@0
|
306 * Do not use this function to load an install file, use module_load_install()
|
danielebarchiesi@0
|
307 * instead. Do not use this function in a global context since it requires
|
danielebarchiesi@0
|
308 * Drupal to be fully bootstrapped, use require_once DRUPAL_ROOT . '/path/file'
|
danielebarchiesi@0
|
309 * instead.
|
danielebarchiesi@0
|
310 *
|
danielebarchiesi@0
|
311 * @param $type
|
danielebarchiesi@0
|
312 * The include file's type (file extension).
|
danielebarchiesi@0
|
313 * @param $module
|
danielebarchiesi@0
|
314 * The module to which the include file belongs.
|
danielebarchiesi@0
|
315 * @param $name
|
danielebarchiesi@0
|
316 * (optional) The base file name (without the $type extension). If omitted,
|
danielebarchiesi@0
|
317 * $module is used; i.e., resulting in "$module.$type" by default.
|
danielebarchiesi@0
|
318 *
|
danielebarchiesi@0
|
319 * @return
|
danielebarchiesi@0
|
320 * The name of the included file, if successful; FALSE otherwise.
|
danielebarchiesi@0
|
321 */
|
danielebarchiesi@0
|
322 function module_load_include($type, $module, $name = NULL) {
|
danielebarchiesi@0
|
323 if (!isset($name)) {
|
danielebarchiesi@0
|
324 $name = $module;
|
danielebarchiesi@0
|
325 }
|
danielebarchiesi@0
|
326
|
danielebarchiesi@0
|
327 if (function_exists('drupal_get_path')) {
|
danielebarchiesi@0
|
328 $file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
|
danielebarchiesi@0
|
329 if (is_file($file)) {
|
danielebarchiesi@0
|
330 require_once $file;
|
danielebarchiesi@0
|
331 return $file;
|
danielebarchiesi@0
|
332 }
|
danielebarchiesi@0
|
333 }
|
danielebarchiesi@0
|
334 return FALSE;
|
danielebarchiesi@0
|
335 }
|
danielebarchiesi@0
|
336
|
danielebarchiesi@0
|
337 /**
|
danielebarchiesi@0
|
338 * Loads an include file for each module enabled in the {system} table.
|
danielebarchiesi@0
|
339 */
|
danielebarchiesi@0
|
340 function module_load_all_includes($type, $name = NULL) {
|
danielebarchiesi@0
|
341 $modules = module_list();
|
danielebarchiesi@0
|
342 foreach ($modules as $module) {
|
danielebarchiesi@0
|
343 module_load_include($type, $module, $name);
|
danielebarchiesi@0
|
344 }
|
danielebarchiesi@0
|
345 }
|
danielebarchiesi@0
|
346
|
danielebarchiesi@0
|
347 /**
|
danielebarchiesi@0
|
348 * Enables or installs a given list of modules.
|
danielebarchiesi@0
|
349 *
|
danielebarchiesi@0
|
350 * Definitions:
|
danielebarchiesi@0
|
351 * - "Enabling" is the process of activating a module for use by Drupal.
|
danielebarchiesi@0
|
352 * - "Disabling" is the process of deactivating a module.
|
danielebarchiesi@0
|
353 * - "Installing" is the process of enabling it for the first time or after it
|
danielebarchiesi@0
|
354 * has been uninstalled.
|
danielebarchiesi@0
|
355 * - "Uninstalling" is the process of removing all traces of a module.
|
danielebarchiesi@0
|
356 *
|
danielebarchiesi@0
|
357 * Order of events:
|
danielebarchiesi@0
|
358 * - Gather and add module dependencies to $module_list (if applicable).
|
danielebarchiesi@0
|
359 * - For each module that is being enabled:
|
danielebarchiesi@0
|
360 * - Install module schema and update system registries and caches.
|
danielebarchiesi@0
|
361 * - If the module is being enabled for the first time or had been
|
danielebarchiesi@0
|
362 * uninstalled, invoke hook_install() and add it to the list of installed
|
danielebarchiesi@0
|
363 * modules.
|
danielebarchiesi@0
|
364 * - Invoke hook_enable().
|
danielebarchiesi@0
|
365 * - Invoke hook_modules_installed().
|
danielebarchiesi@0
|
366 * - Invoke hook_modules_enabled().
|
danielebarchiesi@0
|
367 *
|
danielebarchiesi@0
|
368 * @param $module_list
|
danielebarchiesi@0
|
369 * An array of module names.
|
danielebarchiesi@0
|
370 * @param $enable_dependencies
|
danielebarchiesi@0
|
371 * If TRUE, dependencies will automatically be added and enabled in the
|
danielebarchiesi@0
|
372 * correct order. This incurs a significant performance cost, so use FALSE
|
danielebarchiesi@0
|
373 * if you know $module_list is already complete and in the correct order.
|
danielebarchiesi@0
|
374 *
|
danielebarchiesi@0
|
375 * @return
|
danielebarchiesi@0
|
376 * FALSE if one or more dependencies are missing, TRUE otherwise.
|
danielebarchiesi@0
|
377 *
|
danielebarchiesi@0
|
378 * @see hook_install()
|
danielebarchiesi@0
|
379 * @see hook_enable()
|
danielebarchiesi@0
|
380 * @see hook_modules_installed()
|
danielebarchiesi@0
|
381 * @see hook_modules_enabled()
|
danielebarchiesi@0
|
382 */
|
danielebarchiesi@0
|
383 function module_enable($module_list, $enable_dependencies = TRUE) {
|
danielebarchiesi@0
|
384 if ($enable_dependencies) {
|
danielebarchiesi@0
|
385 // Get all module data so we can find dependencies and sort.
|
danielebarchiesi@0
|
386 $module_data = system_rebuild_module_data();
|
danielebarchiesi@0
|
387 // Create an associative array with weights as values.
|
danielebarchiesi@0
|
388 $module_list = array_flip(array_values($module_list));
|
danielebarchiesi@0
|
389
|
danielebarchiesi@0
|
390 while (list($module) = each($module_list)) {
|
danielebarchiesi@0
|
391 if (!isset($module_data[$module])) {
|
danielebarchiesi@0
|
392 // This module is not found in the filesystem, abort.
|
danielebarchiesi@0
|
393 return FALSE;
|
danielebarchiesi@0
|
394 }
|
danielebarchiesi@0
|
395 if ($module_data[$module]->status) {
|
danielebarchiesi@0
|
396 // Skip already enabled modules.
|
danielebarchiesi@0
|
397 unset($module_list[$module]);
|
danielebarchiesi@0
|
398 continue;
|
danielebarchiesi@0
|
399 }
|
danielebarchiesi@0
|
400 $module_list[$module] = $module_data[$module]->sort;
|
danielebarchiesi@0
|
401
|
danielebarchiesi@0
|
402 // Add dependencies to the list, with a placeholder weight.
|
danielebarchiesi@0
|
403 // The new modules will be processed as the while loop continues.
|
danielebarchiesi@0
|
404 foreach (array_keys($module_data[$module]->requires) as $dependency) {
|
danielebarchiesi@0
|
405 if (!isset($module_list[$dependency])) {
|
danielebarchiesi@0
|
406 $module_list[$dependency] = 0;
|
danielebarchiesi@0
|
407 }
|
danielebarchiesi@0
|
408 }
|
danielebarchiesi@0
|
409 }
|
danielebarchiesi@0
|
410
|
danielebarchiesi@0
|
411 if (!$module_list) {
|
danielebarchiesi@0
|
412 // Nothing to do. All modules already enabled.
|
danielebarchiesi@0
|
413 return TRUE;
|
danielebarchiesi@0
|
414 }
|
danielebarchiesi@0
|
415
|
danielebarchiesi@0
|
416 // Sort the module list by pre-calculated weights.
|
danielebarchiesi@0
|
417 arsort($module_list);
|
danielebarchiesi@0
|
418 $module_list = array_keys($module_list);
|
danielebarchiesi@0
|
419 }
|
danielebarchiesi@0
|
420
|
danielebarchiesi@0
|
421 // Required for module installation checks.
|
danielebarchiesi@0
|
422 include_once DRUPAL_ROOT . '/includes/install.inc';
|
danielebarchiesi@0
|
423
|
danielebarchiesi@0
|
424 $modules_installed = array();
|
danielebarchiesi@0
|
425 $modules_enabled = array();
|
danielebarchiesi@0
|
426 foreach ($module_list as $module) {
|
danielebarchiesi@0
|
427 // Only process modules that are not already enabled.
|
danielebarchiesi@0
|
428 $existing = db_query("SELECT status FROM {system} WHERE type = :type AND name = :name", array(
|
danielebarchiesi@0
|
429 ':type' => 'module',
|
danielebarchiesi@0
|
430 ':name' => $module))
|
danielebarchiesi@0
|
431 ->fetchObject();
|
danielebarchiesi@0
|
432 if ($existing->status == 0) {
|
danielebarchiesi@0
|
433 // Load the module's code.
|
danielebarchiesi@0
|
434 drupal_load('module', $module);
|
danielebarchiesi@0
|
435 module_load_install($module);
|
danielebarchiesi@0
|
436
|
danielebarchiesi@0
|
437 // Update the database and module list to reflect the new module. This
|
danielebarchiesi@0
|
438 // needs to be done first so that the module's hook implementations,
|
danielebarchiesi@0
|
439 // hook_schema() in particular, can be called while it is being
|
danielebarchiesi@0
|
440 // installed.
|
danielebarchiesi@0
|
441 db_update('system')
|
danielebarchiesi@0
|
442 ->fields(array('status' => 1))
|
danielebarchiesi@0
|
443 ->condition('type', 'module')
|
danielebarchiesi@0
|
444 ->condition('name', $module)
|
danielebarchiesi@0
|
445 ->execute();
|
danielebarchiesi@0
|
446 // Refresh the module list to include it.
|
danielebarchiesi@0
|
447 system_list_reset();
|
danielebarchiesi@0
|
448 module_list(TRUE);
|
danielebarchiesi@0
|
449 module_implements('', FALSE, TRUE);
|
danielebarchiesi@0
|
450 _system_update_bootstrap_status();
|
danielebarchiesi@0
|
451 // Update the registry to include it.
|
danielebarchiesi@0
|
452 registry_update();
|
danielebarchiesi@0
|
453 // Refresh the schema to include it.
|
danielebarchiesi@0
|
454 drupal_get_schema(NULL, TRUE);
|
danielebarchiesi@0
|
455 // Update the theme registry to include it.
|
danielebarchiesi@0
|
456 drupal_theme_rebuild();
|
danielebarchiesi@0
|
457 // Clear entity cache.
|
danielebarchiesi@0
|
458 entity_info_cache_clear();
|
danielebarchiesi@0
|
459
|
danielebarchiesi@0
|
460 // Now install the module if necessary.
|
danielebarchiesi@0
|
461 if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
|
danielebarchiesi@0
|
462 drupal_install_schema($module);
|
danielebarchiesi@0
|
463
|
danielebarchiesi@0
|
464 // Set the schema version to the number of the last update provided
|
danielebarchiesi@0
|
465 // by the module.
|
danielebarchiesi@0
|
466 $versions = drupal_get_schema_versions($module);
|
danielebarchiesi@0
|
467 $version = $versions ? max($versions) : SCHEMA_INSTALLED;
|
danielebarchiesi@0
|
468
|
danielebarchiesi@0
|
469 // If the module has no current updates, but has some that were
|
danielebarchiesi@0
|
470 // previously removed, set the version to the value of
|
danielebarchiesi@0
|
471 // hook_update_last_removed().
|
danielebarchiesi@0
|
472 if ($last_removed = module_invoke($module, 'update_last_removed')) {
|
danielebarchiesi@0
|
473 $version = max($version, $last_removed);
|
danielebarchiesi@0
|
474 }
|
danielebarchiesi@0
|
475 drupal_set_installed_schema_version($module, $version);
|
danielebarchiesi@0
|
476 // Allow the module to perform install tasks.
|
danielebarchiesi@0
|
477 module_invoke($module, 'install');
|
danielebarchiesi@0
|
478 // Record the fact that it was installed.
|
danielebarchiesi@0
|
479 $modules_installed[] = $module;
|
danielebarchiesi@0
|
480 watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
|
danielebarchiesi@0
|
481 }
|
danielebarchiesi@0
|
482
|
danielebarchiesi@0
|
483 // Enable the module.
|
danielebarchiesi@0
|
484 module_invoke($module, 'enable');
|
danielebarchiesi@0
|
485
|
danielebarchiesi@0
|
486 // Record the fact that it was enabled.
|
danielebarchiesi@0
|
487 $modules_enabled[] = $module;
|
danielebarchiesi@0
|
488 watchdog('system', '%module module enabled.', array('%module' => $module), WATCHDOG_INFO);
|
danielebarchiesi@0
|
489 }
|
danielebarchiesi@0
|
490 }
|
danielebarchiesi@0
|
491
|
danielebarchiesi@0
|
492 // If any modules were newly installed, invoke hook_modules_installed().
|
danielebarchiesi@0
|
493 if (!empty($modules_installed)) {
|
danielebarchiesi@0
|
494 module_invoke_all('modules_installed', $modules_installed);
|
danielebarchiesi@0
|
495 }
|
danielebarchiesi@0
|
496
|
danielebarchiesi@0
|
497 // If any modules were newly enabled, invoke hook_modules_enabled().
|
danielebarchiesi@0
|
498 if (!empty($modules_enabled)) {
|
danielebarchiesi@0
|
499 module_invoke_all('modules_enabled', $modules_enabled);
|
danielebarchiesi@0
|
500 }
|
danielebarchiesi@0
|
501
|
danielebarchiesi@0
|
502 return TRUE;
|
danielebarchiesi@0
|
503 }
|
danielebarchiesi@0
|
504
|
danielebarchiesi@0
|
505 /**
|
danielebarchiesi@0
|
506 * Disables a given set of modules.
|
danielebarchiesi@0
|
507 *
|
danielebarchiesi@0
|
508 * @param $module_list
|
danielebarchiesi@0
|
509 * An array of module names.
|
danielebarchiesi@0
|
510 * @param $disable_dependents
|
danielebarchiesi@0
|
511 * If TRUE, dependent modules will automatically be added and disabled in the
|
danielebarchiesi@0
|
512 * correct order. This incurs a significant performance cost, so use FALSE
|
danielebarchiesi@0
|
513 * if you know $module_list is already complete and in the correct order.
|
danielebarchiesi@0
|
514 */
|
danielebarchiesi@0
|
515 function module_disable($module_list, $disable_dependents = TRUE) {
|
danielebarchiesi@0
|
516 if ($disable_dependents) {
|
danielebarchiesi@0
|
517 // Get all module data so we can find dependents and sort.
|
danielebarchiesi@0
|
518 $module_data = system_rebuild_module_data();
|
danielebarchiesi@0
|
519 // Create an associative array with weights as values.
|
danielebarchiesi@0
|
520 $module_list = array_flip(array_values($module_list));
|
danielebarchiesi@0
|
521
|
danielebarchiesi@0
|
522 $profile = drupal_get_profile();
|
danielebarchiesi@0
|
523 while (list($module) = each($module_list)) {
|
danielebarchiesi@0
|
524 if (!isset($module_data[$module]) || !$module_data[$module]->status) {
|
danielebarchiesi@0
|
525 // This module doesn't exist or is already disabled, skip it.
|
danielebarchiesi@0
|
526 unset($module_list[$module]);
|
danielebarchiesi@0
|
527 continue;
|
danielebarchiesi@0
|
528 }
|
danielebarchiesi@0
|
529 $module_list[$module] = $module_data[$module]->sort;
|
danielebarchiesi@0
|
530
|
danielebarchiesi@0
|
531 // Add dependent modules to the list, with a placeholder weight.
|
danielebarchiesi@0
|
532 // The new modules will be processed as the while loop continues.
|
danielebarchiesi@0
|
533 foreach ($module_data[$module]->required_by as $dependent => $dependent_data) {
|
danielebarchiesi@0
|
534 if (!isset($module_list[$dependent]) && $dependent != $profile) {
|
danielebarchiesi@0
|
535 $module_list[$dependent] = 0;
|
danielebarchiesi@0
|
536 }
|
danielebarchiesi@0
|
537 }
|
danielebarchiesi@0
|
538 }
|
danielebarchiesi@0
|
539
|
danielebarchiesi@0
|
540 // Sort the module list by pre-calculated weights.
|
danielebarchiesi@0
|
541 asort($module_list);
|
danielebarchiesi@0
|
542 $module_list = array_keys($module_list);
|
danielebarchiesi@0
|
543 }
|
danielebarchiesi@0
|
544
|
danielebarchiesi@0
|
545 $invoke_modules = array();
|
danielebarchiesi@0
|
546
|
danielebarchiesi@0
|
547 foreach ($module_list as $module) {
|
danielebarchiesi@0
|
548 if (module_exists($module)) {
|
danielebarchiesi@0
|
549 // Check if node_access table needs rebuilding.
|
danielebarchiesi@0
|
550 if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
|
danielebarchiesi@0
|
551 node_access_needs_rebuild(TRUE);
|
danielebarchiesi@0
|
552 }
|
danielebarchiesi@0
|
553
|
danielebarchiesi@0
|
554 module_load_install($module);
|
danielebarchiesi@0
|
555 module_invoke($module, 'disable');
|
danielebarchiesi@0
|
556 db_update('system')
|
danielebarchiesi@0
|
557 ->fields(array('status' => 0))
|
danielebarchiesi@0
|
558 ->condition('type', 'module')
|
danielebarchiesi@0
|
559 ->condition('name', $module)
|
danielebarchiesi@0
|
560 ->execute();
|
danielebarchiesi@0
|
561 $invoke_modules[] = $module;
|
danielebarchiesi@0
|
562 watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO);
|
danielebarchiesi@0
|
563 }
|
danielebarchiesi@0
|
564 }
|
danielebarchiesi@0
|
565
|
danielebarchiesi@0
|
566 if (!empty($invoke_modules)) {
|
danielebarchiesi@0
|
567 // Refresh the module list to exclude the disabled modules.
|
danielebarchiesi@0
|
568 system_list_reset();
|
danielebarchiesi@0
|
569 module_list(TRUE);
|
danielebarchiesi@0
|
570 module_implements('', FALSE, TRUE);
|
danielebarchiesi@0
|
571 entity_info_cache_clear();
|
danielebarchiesi@0
|
572 // Invoke hook_modules_disabled before disabling modules,
|
danielebarchiesi@0
|
573 // so we can still call module hooks to get information.
|
danielebarchiesi@0
|
574 module_invoke_all('modules_disabled', $invoke_modules);
|
danielebarchiesi@0
|
575 // Update the registry to remove the newly-disabled module.
|
danielebarchiesi@0
|
576 registry_update();
|
danielebarchiesi@0
|
577 _system_update_bootstrap_status();
|
danielebarchiesi@0
|
578 // Update the theme registry to remove the newly-disabled module.
|
danielebarchiesi@0
|
579 drupal_theme_rebuild();
|
danielebarchiesi@0
|
580 }
|
danielebarchiesi@0
|
581
|
danielebarchiesi@0
|
582 // If there remains no more node_access module, rebuilding will be
|
danielebarchiesi@0
|
583 // straightforward, we can do it right now.
|
danielebarchiesi@0
|
584 if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
|
danielebarchiesi@0
|
585 node_access_rebuild();
|
danielebarchiesi@0
|
586 }
|
danielebarchiesi@0
|
587 }
|
danielebarchiesi@0
|
588
|
danielebarchiesi@0
|
589 /**
|
danielebarchiesi@0
|
590 * @defgroup hooks Hooks
|
danielebarchiesi@0
|
591 * @{
|
danielebarchiesi@0
|
592 * Allow modules to interact with the Drupal core.
|
danielebarchiesi@0
|
593 *
|
danielebarchiesi@0
|
594 * Drupal's module system is based on the concept of "hooks". A hook is a PHP
|
danielebarchiesi@0
|
595 * function that is named foo_bar(), where "foo" is the name of the module
|
danielebarchiesi@0
|
596 * (whose filename is thus foo.module) and "bar" is the name of the hook. Each
|
danielebarchiesi@0
|
597 * hook has a defined set of parameters and a specified result type.
|
danielebarchiesi@0
|
598 *
|
danielebarchiesi@0
|
599 * To extend Drupal, a module need simply implement a hook. When Drupal wishes
|
danielebarchiesi@0
|
600 * to allow intervention from modules, it determines which modules implement a
|
danielebarchiesi@0
|
601 * hook and calls that hook in all enabled modules that implement it.
|
danielebarchiesi@0
|
602 *
|
danielebarchiesi@0
|
603 * The available hooks to implement are explained here in the Hooks section of
|
danielebarchiesi@0
|
604 * the developer documentation. The string "hook" is used as a placeholder for
|
danielebarchiesi@0
|
605 * the module name in the hook definitions. For example, if the module file is
|
danielebarchiesi@0
|
606 * called example.module, then hook_help() as implemented by that module would
|
danielebarchiesi@0
|
607 * be defined as example_help().
|
danielebarchiesi@0
|
608 *
|
danielebarchiesi@0
|
609 * The example functions included are not part of the Drupal core, they are
|
danielebarchiesi@0
|
610 * just models that you can modify. Only the hooks implemented within modules
|
danielebarchiesi@0
|
611 * are executed when running Drupal.
|
danielebarchiesi@0
|
612 *
|
danielebarchiesi@0
|
613 * @see themeable
|
danielebarchiesi@0
|
614 * @see callbacks
|
danielebarchiesi@0
|
615 */
|
danielebarchiesi@0
|
616
|
danielebarchiesi@0
|
617 /**
|
danielebarchiesi@0
|
618 * @defgroup callbacks Callbacks
|
danielebarchiesi@0
|
619 * @{
|
danielebarchiesi@0
|
620 * Callback function signatures.
|
danielebarchiesi@0
|
621 *
|
danielebarchiesi@0
|
622 * Drupal's API sometimes uses callback functions to allow you to define how
|
danielebarchiesi@0
|
623 * some type of processing happens. A callback is a function with a defined
|
danielebarchiesi@0
|
624 * signature, which you define in a module. Then you pass the function name as
|
danielebarchiesi@0
|
625 * a parameter to a Drupal API function or return it as part of a hook
|
danielebarchiesi@0
|
626 * implementation return value, and your function is called at an appropriate
|
danielebarchiesi@0
|
627 * time. For instance, when setting up batch processing you might need to
|
danielebarchiesi@0
|
628 * provide a callback function for each processing step and/or a callback for
|
danielebarchiesi@0
|
629 * when processing is finished; you would do that by defining these functions
|
danielebarchiesi@0
|
630 * and passing their names into the batch setup function.
|
danielebarchiesi@0
|
631 *
|
danielebarchiesi@0
|
632 * Callback function signatures, like hook definitions, are described by
|
danielebarchiesi@0
|
633 * creating and documenting dummy functions in a *.api.php file; normally, the
|
danielebarchiesi@0
|
634 * dummy callback function's name should start with "callback_", and you should
|
danielebarchiesi@0
|
635 * document the parameters and return value and provide a sample function body.
|
danielebarchiesi@0
|
636 * Then your API documentation can refer to this callback function in its
|
danielebarchiesi@0
|
637 * documentation. A user of your API can usually name their callback function
|
danielebarchiesi@0
|
638 * anything they want, although a standard name would be to replace "callback_"
|
danielebarchiesi@0
|
639 * with the module name.
|
danielebarchiesi@0
|
640 *
|
danielebarchiesi@0
|
641 * @see hooks
|
danielebarchiesi@0
|
642 * @see themeable
|
danielebarchiesi@0
|
643 *
|
danielebarchiesi@0
|
644 * @}
|
danielebarchiesi@0
|
645 */
|
danielebarchiesi@0
|
646
|
danielebarchiesi@0
|
647 /**
|
danielebarchiesi@0
|
648 * Determines whether a module implements a hook.
|
danielebarchiesi@0
|
649 *
|
danielebarchiesi@0
|
650 * @param $module
|
danielebarchiesi@0
|
651 * The name of the module (without the .module extension).
|
danielebarchiesi@0
|
652 * @param $hook
|
danielebarchiesi@0
|
653 * The name of the hook (e.g. "help" or "menu").
|
danielebarchiesi@0
|
654 *
|
danielebarchiesi@0
|
655 * @return
|
danielebarchiesi@0
|
656 * TRUE if the module is both installed and enabled, and the hook is
|
danielebarchiesi@0
|
657 * implemented in that module.
|
danielebarchiesi@0
|
658 */
|
danielebarchiesi@0
|
659 function module_hook($module, $hook) {
|
danielebarchiesi@0
|
660 $function = $module . '_' . $hook;
|
danielebarchiesi@0
|
661 if (function_exists($function)) {
|
danielebarchiesi@0
|
662 return TRUE;
|
danielebarchiesi@0
|
663 }
|
danielebarchiesi@0
|
664 // If the hook implementation does not exist, check whether it may live in an
|
danielebarchiesi@0
|
665 // optional include file registered via hook_hook_info().
|
danielebarchiesi@0
|
666 $hook_info = module_hook_info();
|
danielebarchiesi@0
|
667 if (isset($hook_info[$hook]['group'])) {
|
danielebarchiesi@0
|
668 module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
|
danielebarchiesi@0
|
669 if (function_exists($function)) {
|
danielebarchiesi@0
|
670 return TRUE;
|
danielebarchiesi@0
|
671 }
|
danielebarchiesi@0
|
672 }
|
danielebarchiesi@0
|
673 return FALSE;
|
danielebarchiesi@0
|
674 }
|
danielebarchiesi@0
|
675
|
danielebarchiesi@0
|
676 /**
|
danielebarchiesi@0
|
677 * Determines which modules are implementing a hook.
|
danielebarchiesi@0
|
678 *
|
danielebarchiesi@0
|
679 * @param $hook
|
danielebarchiesi@0
|
680 * The name of the hook (e.g. "help" or "menu").
|
danielebarchiesi@0
|
681 * @param $sort
|
danielebarchiesi@0
|
682 * By default, modules are ordered by weight and filename, settings this option
|
danielebarchiesi@0
|
683 * to TRUE, module list will be ordered by module name.
|
danielebarchiesi@0
|
684 * @param $reset
|
danielebarchiesi@0
|
685 * For internal use only: Whether to force the stored list of hook
|
danielebarchiesi@0
|
686 * implementations to be regenerated (such as after enabling a new module,
|
danielebarchiesi@0
|
687 * before processing hook_enable).
|
danielebarchiesi@0
|
688 *
|
danielebarchiesi@0
|
689 * @return
|
danielebarchiesi@0
|
690 * An array with the names of the modules which are implementing this hook.
|
danielebarchiesi@0
|
691 *
|
danielebarchiesi@0
|
692 * @see module_implements_write_cache()
|
danielebarchiesi@0
|
693 */
|
danielebarchiesi@0
|
694 function module_implements($hook, $sort = FALSE, $reset = FALSE) {
|
danielebarchiesi@0
|
695 // Use the advanced drupal_static() pattern, since this is called very often.
|
danielebarchiesi@0
|
696 static $drupal_static_fast;
|
danielebarchiesi@0
|
697 if (!isset($drupal_static_fast)) {
|
danielebarchiesi@0
|
698 $drupal_static_fast['implementations'] = &drupal_static(__FUNCTION__);
|
danielebarchiesi@0
|
699 }
|
danielebarchiesi@0
|
700 $implementations = &$drupal_static_fast['implementations'];
|
danielebarchiesi@0
|
701
|
danielebarchiesi@0
|
702 // We maintain a persistent cache of hook implementations in addition to the
|
danielebarchiesi@0
|
703 // static cache to avoid looping through every module and every hook on each
|
danielebarchiesi@0
|
704 // request. Benchmarks show that the benefit of this caching outweighs the
|
danielebarchiesi@0
|
705 // additional database hit even when using the default database caching
|
danielebarchiesi@0
|
706 // backend and only a small number of modules are enabled. The cost of the
|
danielebarchiesi@0
|
707 // cache_get() is more or less constant and reduced further when non-database
|
danielebarchiesi@0
|
708 // caching backends are used, so there will be more significant gains when a
|
danielebarchiesi@0
|
709 // large number of modules are installed or hooks invoked, since this can
|
danielebarchiesi@0
|
710 // quickly lead to module_hook() being called several thousand times
|
danielebarchiesi@0
|
711 // per request.
|
danielebarchiesi@0
|
712 if ($reset) {
|
danielebarchiesi@0
|
713 $implementations = array();
|
danielebarchiesi@0
|
714 cache_set('module_implements', array(), 'cache_bootstrap');
|
danielebarchiesi@0
|
715 drupal_static_reset('module_hook_info');
|
danielebarchiesi@0
|
716 drupal_static_reset('drupal_alter');
|
danielebarchiesi@0
|
717 cache_clear_all('hook_info', 'cache_bootstrap');
|
danielebarchiesi@0
|
718 return;
|
danielebarchiesi@0
|
719 }
|
danielebarchiesi@0
|
720
|
danielebarchiesi@0
|
721 // Fetch implementations from cache.
|
danielebarchiesi@0
|
722 if (empty($implementations)) {
|
danielebarchiesi@0
|
723 $implementations = cache_get('module_implements', 'cache_bootstrap');
|
danielebarchiesi@0
|
724 if ($implementations === FALSE) {
|
danielebarchiesi@0
|
725 $implementations = array();
|
danielebarchiesi@0
|
726 }
|
danielebarchiesi@0
|
727 else {
|
danielebarchiesi@0
|
728 $implementations = $implementations->data;
|
danielebarchiesi@0
|
729 }
|
danielebarchiesi@0
|
730 }
|
danielebarchiesi@0
|
731
|
danielebarchiesi@0
|
732 if (!isset($implementations[$hook])) {
|
danielebarchiesi@0
|
733 // The hook is not cached, so ensure that whether or not it has
|
danielebarchiesi@0
|
734 // implementations, that the cache is updated at the end of the request.
|
danielebarchiesi@0
|
735 $implementations['#write_cache'] = TRUE;
|
danielebarchiesi@0
|
736 $hook_info = module_hook_info();
|
danielebarchiesi@0
|
737 $implementations[$hook] = array();
|
danielebarchiesi@0
|
738 $list = module_list(FALSE, FALSE, $sort);
|
danielebarchiesi@0
|
739 foreach ($list as $module) {
|
danielebarchiesi@0
|
740 $include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
|
danielebarchiesi@0
|
741 // Since module_hook() may needlessly try to load the include file again,
|
danielebarchiesi@0
|
742 // function_exists() is used directly here.
|
danielebarchiesi@0
|
743 if (function_exists($module . '_' . $hook)) {
|
danielebarchiesi@0
|
744 $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
|
danielebarchiesi@0
|
745 }
|
danielebarchiesi@0
|
746 }
|
danielebarchiesi@0
|
747 // Allow modules to change the weight of specific implementations but avoid
|
danielebarchiesi@0
|
748 // an infinite loop.
|
danielebarchiesi@0
|
749 if ($hook != 'module_implements_alter') {
|
danielebarchiesi@0
|
750 drupal_alter('module_implements', $implementations[$hook], $hook);
|
danielebarchiesi@0
|
751 }
|
danielebarchiesi@0
|
752 }
|
danielebarchiesi@0
|
753 else {
|
danielebarchiesi@0
|
754 foreach ($implementations[$hook] as $module => $group) {
|
danielebarchiesi@0
|
755 // If this hook implementation is stored in a lazy-loaded file, so include
|
danielebarchiesi@0
|
756 // that file first.
|
danielebarchiesi@0
|
757 if ($group) {
|
danielebarchiesi@0
|
758 module_load_include('inc', $module, "$module.$group");
|
danielebarchiesi@0
|
759 }
|
danielebarchiesi@0
|
760 // It is possible that a module removed a hook implementation without the
|
danielebarchiesi@0
|
761 // implementations cache being rebuilt yet, so we check whether the
|
danielebarchiesi@0
|
762 // function exists on each request to avoid undefined function errors.
|
danielebarchiesi@0
|
763 // Since module_hook() may needlessly try to load the include file again,
|
danielebarchiesi@0
|
764 // function_exists() is used directly here.
|
danielebarchiesi@0
|
765 if (!function_exists($module . '_' . $hook)) {
|
danielebarchiesi@0
|
766 // Clear out the stale implementation from the cache and force a cache
|
danielebarchiesi@0
|
767 // refresh to forget about no longer existing hook implementations.
|
danielebarchiesi@0
|
768 unset($implementations[$hook][$module]);
|
danielebarchiesi@0
|
769 $implementations['#write_cache'] = TRUE;
|
danielebarchiesi@0
|
770 }
|
danielebarchiesi@0
|
771 }
|
danielebarchiesi@0
|
772 }
|
danielebarchiesi@0
|
773
|
danielebarchiesi@0
|
774 return array_keys($implementations[$hook]);
|
danielebarchiesi@0
|
775 }
|
danielebarchiesi@0
|
776
|
danielebarchiesi@0
|
777 /**
|
danielebarchiesi@0
|
778 * Retrieves a list of hooks that are declared through hook_hook_info().
|
danielebarchiesi@0
|
779 *
|
danielebarchiesi@0
|
780 * @return
|
danielebarchiesi@0
|
781 * An associative array whose keys are hook names and whose values are an
|
danielebarchiesi@0
|
782 * associative array containing a group name. The structure of the array
|
danielebarchiesi@0
|
783 * is the same as the return value of hook_hook_info().
|
danielebarchiesi@0
|
784 *
|
danielebarchiesi@0
|
785 * @see hook_hook_info()
|
danielebarchiesi@0
|
786 */
|
danielebarchiesi@0
|
787 function module_hook_info() {
|
danielebarchiesi@0
|
788 // This function is indirectly invoked from bootstrap_invoke_all(), in which
|
danielebarchiesi@0
|
789 // case common.inc, subsystems, and modules are not loaded yet, so it does not
|
danielebarchiesi@0
|
790 // make sense to support hook groups resp. lazy-loaded include files prior to
|
danielebarchiesi@0
|
791 // full bootstrap.
|
danielebarchiesi@0
|
792 if (drupal_bootstrap(NULL, FALSE) != DRUPAL_BOOTSTRAP_FULL) {
|
danielebarchiesi@0
|
793 return array();
|
danielebarchiesi@0
|
794 }
|
danielebarchiesi@0
|
795 $hook_info = &drupal_static(__FUNCTION__);
|
danielebarchiesi@0
|
796
|
danielebarchiesi@0
|
797 if (!isset($hook_info)) {
|
danielebarchiesi@0
|
798 $hook_info = array();
|
danielebarchiesi@0
|
799 $cache = cache_get('hook_info', 'cache_bootstrap');
|
danielebarchiesi@0
|
800 if ($cache === FALSE) {
|
danielebarchiesi@0
|
801 // Rebuild the cache and save it.
|
danielebarchiesi@0
|
802 // We can't use module_invoke_all() here or it would cause an infinite
|
danielebarchiesi@0
|
803 // loop.
|
danielebarchiesi@0
|
804 foreach (module_list() as $module) {
|
danielebarchiesi@0
|
805 $function = $module . '_hook_info';
|
danielebarchiesi@0
|
806 if (function_exists($function)) {
|
danielebarchiesi@0
|
807 $result = $function();
|
danielebarchiesi@0
|
808 if (isset($result) && is_array($result)) {
|
danielebarchiesi@0
|
809 $hook_info = array_merge_recursive($hook_info, $result);
|
danielebarchiesi@0
|
810 }
|
danielebarchiesi@0
|
811 }
|
danielebarchiesi@0
|
812 }
|
danielebarchiesi@0
|
813 // We can't use drupal_alter() for the same reason as above.
|
danielebarchiesi@0
|
814 foreach (module_list() as $module) {
|
danielebarchiesi@0
|
815 $function = $module . '_hook_info_alter';
|
danielebarchiesi@0
|
816 if (function_exists($function)) {
|
danielebarchiesi@0
|
817 $function($hook_info);
|
danielebarchiesi@0
|
818 }
|
danielebarchiesi@0
|
819 }
|
danielebarchiesi@0
|
820 cache_set('hook_info', $hook_info, 'cache_bootstrap');
|
danielebarchiesi@0
|
821 }
|
danielebarchiesi@0
|
822 else {
|
danielebarchiesi@0
|
823 $hook_info = $cache->data;
|
danielebarchiesi@0
|
824 }
|
danielebarchiesi@0
|
825 }
|
danielebarchiesi@0
|
826
|
danielebarchiesi@0
|
827 return $hook_info;
|
danielebarchiesi@0
|
828 }
|
danielebarchiesi@0
|
829
|
danielebarchiesi@0
|
830 /**
|
danielebarchiesi@0
|
831 * Writes the hook implementation cache.
|
danielebarchiesi@0
|
832 *
|
danielebarchiesi@0
|
833 * @see module_implements()
|
danielebarchiesi@0
|
834 */
|
danielebarchiesi@0
|
835 function module_implements_write_cache() {
|
danielebarchiesi@0
|
836 $implementations = &drupal_static('module_implements');
|
danielebarchiesi@0
|
837 if (isset($implementations['#write_cache'])) {
|
danielebarchiesi@0
|
838 unset($implementations['#write_cache']);
|
danielebarchiesi@0
|
839 cache_set('module_implements', $implementations, 'cache_bootstrap');
|
danielebarchiesi@0
|
840 }
|
danielebarchiesi@0
|
841 }
|
danielebarchiesi@0
|
842
|
danielebarchiesi@0
|
843 /**
|
danielebarchiesi@0
|
844 * Invokes a hook in a particular module.
|
danielebarchiesi@0
|
845 *
|
danielebarchiesi@0
|
846 * All arguments are passed by value. Use drupal_alter() if you need to pass
|
danielebarchiesi@0
|
847 * arguments by reference.
|
danielebarchiesi@0
|
848 *
|
danielebarchiesi@0
|
849 * @param $module
|
danielebarchiesi@0
|
850 * The name of the module (without the .module extension).
|
danielebarchiesi@0
|
851 * @param $hook
|
danielebarchiesi@0
|
852 * The name of the hook to invoke.
|
danielebarchiesi@0
|
853 * @param ...
|
danielebarchiesi@0
|
854 * Arguments to pass to the hook implementation.
|
danielebarchiesi@0
|
855 *
|
danielebarchiesi@0
|
856 * @return
|
danielebarchiesi@0
|
857 * The return value of the hook implementation.
|
danielebarchiesi@0
|
858 *
|
danielebarchiesi@0
|
859 * @see drupal_alter()
|
danielebarchiesi@0
|
860 */
|
danielebarchiesi@0
|
861 function module_invoke($module, $hook) {
|
danielebarchiesi@0
|
862 $args = func_get_args();
|
danielebarchiesi@0
|
863 // Remove $module and $hook from the arguments.
|
danielebarchiesi@0
|
864 unset($args[0], $args[1]);
|
danielebarchiesi@0
|
865 if (module_hook($module, $hook)) {
|
danielebarchiesi@0
|
866 return call_user_func_array($module . '_' . $hook, $args);
|
danielebarchiesi@0
|
867 }
|
danielebarchiesi@0
|
868 }
|
danielebarchiesi@0
|
869
|
danielebarchiesi@0
|
870 /**
|
danielebarchiesi@0
|
871 * Invokes a hook in all enabled modules that implement it.
|
danielebarchiesi@0
|
872 *
|
danielebarchiesi@0
|
873 * All arguments are passed by value. Use drupal_alter() if you need to pass
|
danielebarchiesi@0
|
874 * arguments by reference.
|
danielebarchiesi@0
|
875 *
|
danielebarchiesi@0
|
876 * @param $hook
|
danielebarchiesi@0
|
877 * The name of the hook to invoke.
|
danielebarchiesi@0
|
878 * @param ...
|
danielebarchiesi@0
|
879 * Arguments to pass to the hook.
|
danielebarchiesi@0
|
880 *
|
danielebarchiesi@0
|
881 * @return
|
danielebarchiesi@0
|
882 * An array of return values of the hook implementations. If modules return
|
danielebarchiesi@0
|
883 * arrays from their implementations, those are merged into one array.
|
danielebarchiesi@0
|
884 *
|
danielebarchiesi@0
|
885 * @see drupal_alter()
|
danielebarchiesi@0
|
886 */
|
danielebarchiesi@0
|
887 function module_invoke_all($hook) {
|
danielebarchiesi@0
|
888 $args = func_get_args();
|
danielebarchiesi@0
|
889 // Remove $hook from the arguments.
|
danielebarchiesi@0
|
890 unset($args[0]);
|
danielebarchiesi@0
|
891 $return = array();
|
danielebarchiesi@0
|
892 foreach (module_implements($hook) as $module) {
|
danielebarchiesi@0
|
893 $function = $module . '_' . $hook;
|
danielebarchiesi@0
|
894 if (function_exists($function)) {
|
danielebarchiesi@0
|
895 $result = call_user_func_array($function, $args);
|
danielebarchiesi@0
|
896 if (isset($result) && is_array($result)) {
|
danielebarchiesi@0
|
897 $return = array_merge_recursive($return, $result);
|
danielebarchiesi@0
|
898 }
|
danielebarchiesi@0
|
899 elseif (isset($result)) {
|
danielebarchiesi@0
|
900 $return[] = $result;
|
danielebarchiesi@0
|
901 }
|
danielebarchiesi@0
|
902 }
|
danielebarchiesi@0
|
903 }
|
danielebarchiesi@0
|
904
|
danielebarchiesi@0
|
905 return $return;
|
danielebarchiesi@0
|
906 }
|
danielebarchiesi@0
|
907
|
danielebarchiesi@0
|
908 /**
|
danielebarchiesi@0
|
909 * @} End of "defgroup hooks".
|
danielebarchiesi@0
|
910 */
|
danielebarchiesi@0
|
911
|
danielebarchiesi@0
|
912 /**
|
danielebarchiesi@0
|
913 * Returns an array of modules required by core.
|
danielebarchiesi@0
|
914 */
|
danielebarchiesi@0
|
915 function drupal_required_modules() {
|
danielebarchiesi@0
|
916 $files = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'modules', 'name', 0);
|
danielebarchiesi@0
|
917 $required = array();
|
danielebarchiesi@0
|
918
|
danielebarchiesi@0
|
919 // An installation profile is required and one must always be loaded.
|
danielebarchiesi@0
|
920 $required[] = drupal_get_profile();
|
danielebarchiesi@0
|
921
|
danielebarchiesi@0
|
922 foreach ($files as $name => $file) {
|
danielebarchiesi@0
|
923 $info = drupal_parse_info_file($file->uri);
|
danielebarchiesi@0
|
924 if (!empty($info) && !empty($info['required']) && $info['required']) {
|
danielebarchiesi@0
|
925 $required[] = $name;
|
danielebarchiesi@0
|
926 }
|
danielebarchiesi@0
|
927 }
|
danielebarchiesi@0
|
928
|
danielebarchiesi@0
|
929 return $required;
|
danielebarchiesi@0
|
930 }
|
danielebarchiesi@0
|
931
|
danielebarchiesi@0
|
932 /**
|
danielebarchiesi@0
|
933 * Passes alterable variables to specific hook_TYPE_alter() implementations.
|
danielebarchiesi@0
|
934 *
|
danielebarchiesi@0
|
935 * This dispatch function hands off the passed-in variables to type-specific
|
danielebarchiesi@0
|
936 * hook_TYPE_alter() implementations in modules. It ensures a consistent
|
danielebarchiesi@0
|
937 * interface for all altering operations.
|
danielebarchiesi@0
|
938 *
|
danielebarchiesi@0
|
939 * A maximum of 2 alterable arguments is supported (a third is supported for
|
danielebarchiesi@0
|
940 * legacy reasons, but should not be used in new code). In case more arguments
|
danielebarchiesi@0
|
941 * need to be passed and alterable, modules provide additional variables
|
danielebarchiesi@0
|
942 * assigned by reference in the last $context argument:
|
danielebarchiesi@0
|
943 * @code
|
danielebarchiesi@0
|
944 * $context = array(
|
danielebarchiesi@0
|
945 * 'alterable' => &$alterable,
|
danielebarchiesi@0
|
946 * 'unalterable' => $unalterable,
|
danielebarchiesi@0
|
947 * 'foo' => 'bar',
|
danielebarchiesi@0
|
948 * );
|
danielebarchiesi@0
|
949 * drupal_alter('mymodule_data', $alterable1, $alterable2, $context);
|
danielebarchiesi@0
|
950 * @endcode
|
danielebarchiesi@0
|
951 *
|
danielebarchiesi@0
|
952 * Note that objects are always passed by reference in PHP5. If it is absolutely
|
danielebarchiesi@0
|
953 * required that no implementation alters a passed object in $context, then an
|
danielebarchiesi@0
|
954 * object needs to be cloned:
|
danielebarchiesi@0
|
955 * @code
|
danielebarchiesi@0
|
956 * $context = array(
|
danielebarchiesi@0
|
957 * 'unalterable_object' => clone $object,
|
danielebarchiesi@0
|
958 * );
|
danielebarchiesi@0
|
959 * drupal_alter('mymodule_data', $data, $context);
|
danielebarchiesi@0
|
960 * @endcode
|
danielebarchiesi@0
|
961 *
|
danielebarchiesi@0
|
962 * @param $type
|
danielebarchiesi@0
|
963 * A string describing the type of the alterable $data. 'form', 'links',
|
danielebarchiesi@0
|
964 * 'node_content', and so on are several examples. Alternatively can be an
|
danielebarchiesi@0
|
965 * array, in which case hook_TYPE_alter() is invoked for each value in the
|
danielebarchiesi@0
|
966 * array, ordered first by module, and then for each module, in the order of
|
danielebarchiesi@0
|
967 * values in $type. For example, when Form API is using drupal_alter() to
|
danielebarchiesi@0
|
968 * execute both hook_form_alter() and hook_form_FORM_ID_alter()
|
danielebarchiesi@0
|
969 * implementations, it passes array('form', 'form_' . $form_id) for $type.
|
danielebarchiesi@0
|
970 * @param $data
|
danielebarchiesi@0
|
971 * The variable that will be passed to hook_TYPE_alter() implementations to be
|
danielebarchiesi@0
|
972 * altered. The type of this variable depends on the value of the $type
|
danielebarchiesi@0
|
973 * argument. For example, when altering a 'form', $data will be a structured
|
danielebarchiesi@0
|
974 * array. When altering a 'profile', $data will be an object.
|
danielebarchiesi@0
|
975 * @param $context1
|
danielebarchiesi@0
|
976 * (optional) An additional variable that is passed by reference.
|
danielebarchiesi@0
|
977 * @param $context2
|
danielebarchiesi@0
|
978 * (optional) An additional variable that is passed by reference. If more
|
danielebarchiesi@0
|
979 * context needs to be provided to implementations, then this should be an
|
danielebarchiesi@0
|
980 * associative array as described above.
|
danielebarchiesi@0
|
981 * @param $context3
|
danielebarchiesi@0
|
982 * (optional) An additional variable that is passed by reference. This
|
danielebarchiesi@0
|
983 * parameter is deprecated and will not exist in Drupal 8; consequently, it
|
danielebarchiesi@0
|
984 * should not be used for new Drupal 7 code either. It is here only for
|
danielebarchiesi@0
|
985 * backwards compatibility with older code that passed additional arguments
|
danielebarchiesi@0
|
986 * to drupal_alter().
|
danielebarchiesi@0
|
987 */
|
danielebarchiesi@0
|
988 function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
|
danielebarchiesi@0
|
989 // Use the advanced drupal_static() pattern, since this is called very often.
|
danielebarchiesi@0
|
990 static $drupal_static_fast;
|
danielebarchiesi@0
|
991 if (!isset($drupal_static_fast)) {
|
danielebarchiesi@0
|
992 $drupal_static_fast['functions'] = &drupal_static(__FUNCTION__);
|
danielebarchiesi@0
|
993 }
|
danielebarchiesi@0
|
994 $functions = &$drupal_static_fast['functions'];
|
danielebarchiesi@0
|
995
|
danielebarchiesi@0
|
996 // Most of the time, $type is passed as a string, so for performance,
|
danielebarchiesi@0
|
997 // normalize it to that. When passed as an array, usually the first item in
|
danielebarchiesi@0
|
998 // the array is a generic type, and additional items in the array are more
|
danielebarchiesi@0
|
999 // specific variants of it, as in the case of array('form', 'form_FORM_ID').
|
danielebarchiesi@0
|
1000 if (is_array($type)) {
|
danielebarchiesi@0
|
1001 $cid = implode(',', $type);
|
danielebarchiesi@0
|
1002 $extra_types = $type;
|
danielebarchiesi@0
|
1003 $type = array_shift($extra_types);
|
danielebarchiesi@0
|
1004 // Allow if statements in this function to use the faster isset() rather
|
danielebarchiesi@0
|
1005 // than !empty() both when $type is passed as a string, or as an array with
|
danielebarchiesi@0
|
1006 // one item.
|
danielebarchiesi@0
|
1007 if (empty($extra_types)) {
|
danielebarchiesi@0
|
1008 unset($extra_types);
|
danielebarchiesi@0
|
1009 }
|
danielebarchiesi@0
|
1010 }
|
danielebarchiesi@0
|
1011 else {
|
danielebarchiesi@0
|
1012 $cid = $type;
|
danielebarchiesi@0
|
1013 }
|
danielebarchiesi@0
|
1014
|
danielebarchiesi@0
|
1015 // Some alter hooks are invoked many times per page request, so statically
|
danielebarchiesi@0
|
1016 // cache the list of functions to call, and on subsequent calls, iterate
|
danielebarchiesi@0
|
1017 // through them quickly.
|
danielebarchiesi@0
|
1018 if (!isset($functions[$cid])) {
|
danielebarchiesi@0
|
1019 $functions[$cid] = array();
|
danielebarchiesi@0
|
1020 $hook = $type . '_alter';
|
danielebarchiesi@0
|
1021 $modules = module_implements($hook);
|
danielebarchiesi@0
|
1022 if (!isset($extra_types)) {
|
danielebarchiesi@0
|
1023 // For the more common case of a single hook, we do not need to call
|
danielebarchiesi@0
|
1024 // function_exists(), since module_implements() returns only modules with
|
danielebarchiesi@0
|
1025 // implementations.
|
danielebarchiesi@0
|
1026 foreach ($modules as $module) {
|
danielebarchiesi@0
|
1027 $functions[$cid][] = $module . '_' . $hook;
|
danielebarchiesi@0
|
1028 }
|
danielebarchiesi@0
|
1029 }
|
danielebarchiesi@0
|
1030 else {
|
danielebarchiesi@0
|
1031 // For multiple hooks, we need $modules to contain every module that
|
danielebarchiesi@0
|
1032 // implements at least one of them.
|
danielebarchiesi@0
|
1033 $extra_modules = array();
|
danielebarchiesi@0
|
1034 foreach ($extra_types as $extra_type) {
|
danielebarchiesi@0
|
1035 $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter'));
|
danielebarchiesi@0
|
1036 }
|
danielebarchiesi@0
|
1037 // If any modules implement one of the extra hooks that do not implement
|
danielebarchiesi@0
|
1038 // the primary hook, we need to add them to the $modules array in their
|
danielebarchiesi@0
|
1039 // appropriate order. module_implements() can only return ordered
|
danielebarchiesi@0
|
1040 // implementations of a single hook. To get the ordered implementations
|
danielebarchiesi@0
|
1041 // of multiple hooks, we mimic the module_implements() logic of first
|
danielebarchiesi@0
|
1042 // ordering by module_list(), and then calling
|
danielebarchiesi@0
|
1043 // drupal_alter('module_implements').
|
danielebarchiesi@0
|
1044 if (array_diff($extra_modules, $modules)) {
|
danielebarchiesi@0
|
1045 // Merge the arrays and order by module_list().
|
danielebarchiesi@0
|
1046 $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
|
danielebarchiesi@0
|
1047 // Since module_implements() already took care of loading the necessary
|
danielebarchiesi@0
|
1048 // include files, we can safely pass FALSE for the array values.
|
danielebarchiesi@0
|
1049 $implementations = array_fill_keys($modules, FALSE);
|
danielebarchiesi@0
|
1050 // Let modules adjust the order solely based on the primary hook. This
|
danielebarchiesi@0
|
1051 // ensures the same module order regardless of whether this if block
|
danielebarchiesi@0
|
1052 // runs. Calling drupal_alter() recursively in this way does not result
|
danielebarchiesi@0
|
1053 // in an infinite loop, because this call is for a single $type, so we
|
danielebarchiesi@0
|
1054 // won't end up in this code block again.
|
danielebarchiesi@0
|
1055 drupal_alter('module_implements', $implementations, $hook);
|
danielebarchiesi@0
|
1056 $modules = array_keys($implementations);
|
danielebarchiesi@0
|
1057 }
|
danielebarchiesi@0
|
1058 foreach ($modules as $module) {
|
danielebarchiesi@0
|
1059 // Since $modules is a merged array, for any given module, we do not
|
danielebarchiesi@0
|
1060 // know whether it has any particular implementation, so we need a
|
danielebarchiesi@0
|
1061 // function_exists().
|
danielebarchiesi@0
|
1062 $function = $module . '_' . $hook;
|
danielebarchiesi@0
|
1063 if (function_exists($function)) {
|
danielebarchiesi@0
|
1064 $functions[$cid][] = $function;
|
danielebarchiesi@0
|
1065 }
|
danielebarchiesi@0
|
1066 foreach ($extra_types as $extra_type) {
|
danielebarchiesi@0
|
1067 $function = $module . '_' . $extra_type . '_alter';
|
danielebarchiesi@0
|
1068 if (function_exists($function)) {
|
danielebarchiesi@0
|
1069 $functions[$cid][] = $function;
|
danielebarchiesi@0
|
1070 }
|
danielebarchiesi@0
|
1071 }
|
danielebarchiesi@0
|
1072 }
|
danielebarchiesi@0
|
1073 }
|
danielebarchiesi@0
|
1074 // Allow the theme to alter variables after the theme system has been
|
danielebarchiesi@0
|
1075 // initialized.
|
danielebarchiesi@0
|
1076 global $theme, $base_theme_info;
|
danielebarchiesi@0
|
1077 if (isset($theme)) {
|
danielebarchiesi@0
|
1078 $theme_keys = array();
|
danielebarchiesi@0
|
1079 foreach ($base_theme_info as $base) {
|
danielebarchiesi@0
|
1080 $theme_keys[] = $base->name;
|
danielebarchiesi@0
|
1081 }
|
danielebarchiesi@0
|
1082 $theme_keys[] = $theme;
|
danielebarchiesi@0
|
1083 foreach ($theme_keys as $theme_key) {
|
danielebarchiesi@0
|
1084 $function = $theme_key . '_' . $hook;
|
danielebarchiesi@0
|
1085 if (function_exists($function)) {
|
danielebarchiesi@0
|
1086 $functions[$cid][] = $function;
|
danielebarchiesi@0
|
1087 }
|
danielebarchiesi@0
|
1088 if (isset($extra_types)) {
|
danielebarchiesi@0
|
1089 foreach ($extra_types as $extra_type) {
|
danielebarchiesi@0
|
1090 $function = $theme_key . '_' . $extra_type . '_alter';
|
danielebarchiesi@0
|
1091 if (function_exists($function)) {
|
danielebarchiesi@0
|
1092 $functions[$cid][] = $function;
|
danielebarchiesi@0
|
1093 }
|
danielebarchiesi@0
|
1094 }
|
danielebarchiesi@0
|
1095 }
|
danielebarchiesi@0
|
1096 }
|
danielebarchiesi@0
|
1097 }
|
danielebarchiesi@0
|
1098 }
|
danielebarchiesi@0
|
1099
|
danielebarchiesi@0
|
1100 foreach ($functions[$cid] as $function) {
|
danielebarchiesi@0
|
1101 $function($data, $context1, $context2, $context3);
|
danielebarchiesi@0
|
1102 }
|
danielebarchiesi@0
|
1103 }
|