diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-08-24 00:10:46 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-08-24 00:10:46 +0000 |
commit | e63e85020b6846c35624f04c60b40f1aa11db3b1 (patch) | |
tree | 908a1151a45ce37ae82dce00fffedb26b33ccde0 /includes | |
parent | 4ae238ea577ed0140df6fd034b06bfd7b0f0cdb4 (diff) | |
download | brdo-e63e85020b6846c35624f04c60b40f1aa11db3b1.tar.gz brdo-e63e85020b6846c35624f04c60b40f1aa11db3b1.tar.bz2 |
Of all the patches to accidentally commit without a message. :( Rolling back registry rip. Let's try that again.
Diffstat (limited to 'includes')
-rw-r--r-- | includes/ajax.inc | 2 | ||||
-rw-r--r-- | includes/bootstrap.inc | 101 | ||||
-rw-r--r-- | includes/common.inc | 57 | ||||
-rw-r--r-- | includes/file.inc | 4 | ||||
-rw-r--r-- | includes/form.inc | 17 | ||||
-rw-r--r-- | includes/image.inc | 4 | ||||
-rw-r--r-- | includes/install.inc | 7 | ||||
-rw-r--r-- | includes/mail.inc | 2 | ||||
-rw-r--r-- | includes/menu.inc | 33 | ||||
-rw-r--r-- | includes/module.inc | 159 | ||||
-rw-r--r-- | includes/registry.inc | 131 | ||||
-rw-r--r-- | includes/stream_wrappers.inc | 3 | ||||
-rw-r--r-- | includes/theme.inc | 31 | ||||
-rw-r--r-- | includes/theme.maintenance.inc | 2 | ||||
-rw-r--r-- | includes/token.inc | 33 | ||||
-rw-r--r-- | includes/xmlrpc.inc | 2 | ||||
-rw-r--r-- | includes/xmlrpcs.inc | 2 |
17 files changed, 364 insertions, 226 deletions
diff --git a/includes/ajax.inc b/includes/ajax.inc index 6a5a25e59..67f507a6c 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -211,7 +211,7 @@ function ajax_form_callback() { // Get the callback function from the clicked button. $ajax = $form_state['clicked_button']['#ajax']; $callback = $ajax['callback']; - if (function_exists($callback)) { + if (drupal_function_exists($callback)) { $html = $callback($form, $form_state); // If the returned value is a string, assume it is HTML and create diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 28c217b90..8508b85a2 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -654,7 +654,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { $mask = "/$name\.$type$/"; } - if (function_exists('drupal_system_listing')) { + if (drupal_function_exists('drupal_system_listing')) { $matches = drupal_system_listing($mask, $dir, 'name', 0); if (!empty($matches[$name]->uri)) { $files[$type][$name] = $matches[$name]->uri; @@ -788,19 +788,6 @@ function drupal_page_is_cacheable($allow_caching = NULL) { } /** - * Call all init or exit hooks without including all modules. - * - * @param $hook - * The name of the bootstrap hook we wish to invoke. - */ -function bootstrap_invoke_all($hook) { - foreach (module_list(TRUE, TRUE) as $module) { - drupal_load('module', $module); - module_invoke($module, $hook); - } -} - -/** * Includes a file with the provided type and name. This prevents * including a theme, engine, module, etc., more than once. * @@ -1092,13 +1079,6 @@ function drupal_serve_page_from_cache(stdClass $cache) { } /** - * Define the critical hooks that force modules to always be loaded. - */ -function bootstrap_hooks() { - return array('boot', 'exit', 'watchdog'); -} - -/** * Unserializes and appends elements from a serialized string. * * @param $obj @@ -1489,14 +1469,15 @@ function _drupal_bootstrap($phase) { // If the skipping of the bootstrap hooks is not enforced, call // hook_boot. if (variable_get('page_cache_invoke_hooks', TRUE)) { - bootstrap_invoke_all('boot'); + require_once DRUPAL_ROOT . '/includes/module.inc'; + module_invoke_all('boot'); } header('X-Drupal-Cache: HIT'); drupal_serve_page_from_cache($cache); // If the skipping of the bootstrap hooks is not enforced, call // hook_exit. if (variable_get('page_cache_invoke_hooks', TRUE)) { - bootstrap_invoke_all('exit'); + module_invoke_all('exit'); } // We are done. exit; @@ -1523,9 +1504,6 @@ function _drupal_bootstrap($phase) { case DRUPAL_BOOTSTRAP_VARIABLES: // Load variables from the database, but do not overwrite variables set in settings.php. $conf = variable_initialize(isset($conf) ? $conf : array()); - // Load bootstrap modules. - require_once DRUPAL_ROOT . '/includes/module.inc'; - module_load_all(TRUE); break; case DRUPAL_BOOTSTRAP_SESSION: @@ -1534,7 +1512,8 @@ function _drupal_bootstrap($phase) { break; case DRUPAL_BOOTSTRAP_PAGE_HEADER: - bootstrap_invoke_all('boot'); + require_once DRUPAL_ROOT . '/includes/module.inc'; + module_invoke_all('boot'); if (!$cache && drupal_page_is_cacheable()) { header('X-Drupal-Cache: MISS'); } @@ -1772,7 +1751,7 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) { // Load the .install files to get hook_schema. // On some databases this function may be called before bootstrap has // been completed, so we force the functions we need to load just in case. - if (function_exists('module_load_all_includes')) { + if (drupal_function_exists('module_load_all_includes')) { // There is currently a bug in module_list() where it caches what it // was last called with, which is not always what you want. @@ -1782,7 +1761,7 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) { // "prime" module_list() here to to values we want, specifically // "yes rebuild the list and don't limit to bootstrap". // TODO: Remove this call after http://drupal.org/node/222109 is fixed. - module_list(TRUE, FALSE); + module_list(TRUE); module_load_all_includes('install'); } @@ -1790,11 +1769,17 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) { // Invoke hook_schema for all modules. foreach (module_implements('schema') as $module) { $current = module_invoke($module, 'schema'); - _drupal_schema_initialize($module, $current); + if (drupal_function_exists('_drupal_schema_initialize')) { + _drupal_schema_initialize($module, $current); + } + $schema = array_merge($schema, $current); } - drupal_alter('schema', $schema); + if (drupal_function_exists('drupal_alter')) { + drupal_alter('schema', $schema); + } + // If the schema is empty, avoid saving it: some database engines require // the schema to perform queries, and this could lead to infinite loops. if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) { @@ -1825,10 +1810,51 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) { */ /** + * Confirm that a function is available. + * + * If the function is already available, this function does nothing. + * If the function is not available, it tries to load the file where the + * function lives. If the file is not available, it returns false, so that it + * can be used as a drop-in replacement for function_exists(). + * + * @param $function + * The name of the function to check or load. + * @return + * TRUE if the function is now available, FALSE otherwise. + */ +function drupal_function_exists($function) { + static $checked = array(); + static $maintenance; + + if (!isset($maintenance)) { + $maintenance = defined('MAINTENANCE_MODE'); + } + + if ($maintenance) { + return function_exists($function); + } + + if (isset($checked[$function])) { + return $checked[$function]; + } + $checked[$function] = FALSE; + + if (function_exists($function)) { + $checked[$function] = TRUE; + return TRUE; + } + + $checked[$function] = _registry_check_code('function', $function); + + return $checked[$function]; +} + +/** * Confirm that an interface is available. * - * This function is rarely called directly. Instead, it is registered as an - * spl_autoload() handler, and PHP calls it for us when necessary. + * This function parallels drupal_function_exists(), but is rarely + * called directly. Instead, it is registered as an spl_autoload() + * handler, and PHP calls it for us when necessary. * * @param $interface * The name of the interface to check or load. @@ -1842,8 +1868,9 @@ function drupal_autoload_interface($interface) { /** * Confirm that a class is available. * - * This function is rarely called directly. Instead, it is registered as an - * spl_autoload() handler, and PHP calls it for us when necessary. + * This function parallels drupal_function_exists(), but is rarely + * called directly. Instead, it is registered as an spl_autoload() + * handler, and PHP calls it for us when necessary. * * @param $class * The name of the class to check or load. @@ -1933,8 +1960,8 @@ function _registry_check_code($type, $name = NULL) { /** * Rescan all enabled modules and rebuild the registry. * - * Rescans all code in modules or includes directories, storing the location of - * each interface or class in the database. + * Rescans all code in modules or includes directory, storing a mapping of + * each function, file, and hook implementation in the database. */ function registry_rebuild() { require_once DRUPAL_ROOT . '/includes/registry.inc'; diff --git a/includes/common.inc b/includes/common.inc index 56166cda8..caaa3f5a4 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1219,7 +1219,7 @@ function t($string, array $args = array(), array $options = array()) { $string = $custom_strings[$options['langcode']][$options['context']][$string]; } // Translate with locale module if enabled. - // We don't use function_exists() here, because it breaks the testing + // We don't use drupal_function_exists() here, because it breaks the testing // framework if the locale module is enabled in the parent site (we cannot // unload functions in PHP). elseif (function_exists('locale') && $options['langcode'] != 'en') { @@ -2319,6 +2319,7 @@ function drupal_page_footer() { ob_flush(); } + module_implements(MODULE_IMPLEMENTS_WRITE_CACHE); _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE); drupal_cache_system_paths(); } @@ -2867,7 +2868,7 @@ function drupal_clear_css_cache() { * - 'file': Path to the file relative to base_path(). * - 'inline': The JavaScript code that should be placed in the given scope. * - 'external': The absolute path to an external JavaScript file that is not - * hosted on the local server. These files will not be aggregated if + * hosted on the local server. These files will not be aggregated if * JavaScript aggregation is enabled. * - 'setting': An array with configuration options as associative array. The * array is directly placed in Drupal.settings. All modules should wrap @@ -3574,6 +3575,14 @@ function _drupal_bootstrap_full() { set_error_handler('_drupal_error_handler'); set_exception_handler('_drupal_exception_handler'); + if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'simpletest') !== FALSE) { + // Valid SimpleTest user-agent, log fatal errors to test specific file + // directory. The user-agent is validated in DRUPAL_BOOTSTRAP_DATABASE + // phase so as long as it is a SimpleTest user-agent it is valid. + ini_set('log_errors', 1); + ini_set('error_log', file_directory_path() . '/error.log'); + } + // Emit the correct charset HTTP header. drupal_set_header('Content-Type', 'text/html; charset=utf-8'); // Detect string handling method @@ -3584,14 +3593,6 @@ function _drupal_bootstrap_full() { module_load_all(); // Make sure all stream wrappers are registered. file_get_stream_wrappers(); - if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'simpletest') !== FALSE) { - // Valid SimpleTest user-agent, log fatal errors to test specific file - // directory. The user-agent is validated in DRUPAL_BOOTSTRAP_DATABASE - // phase so as long as it is a SimpleTest user-agent it is valid. - ini_set('log_errors', 1); - ini_set('error_log', file_directory_path() . '/error.log'); - } - // Let all modules take action before menu system handles the request // We do not want this while running update.php. if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { @@ -3766,7 +3767,7 @@ function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1) $searchdir[] = "$config/$directory"; } - // If the database is not available, we can't use function_exists(), so + // If the database is not available, we can't use drupal_function_exists(), so // we load the file_scan_directory function definition manually. if (!function_exists('file_scan_directory')) { require_once DRUPAL_ROOT . '/includes/file.inc'; @@ -3956,7 +3957,7 @@ function drupal_render(&$elements) { // element is rendered into the final text. if (isset($elements['#pre_render'])) { foreach ($elements['#pre_render'] as $function) { - if (function_exists($function)) { + if (drupal_function_exists($function)) { $elements = $function($elements); } } @@ -3990,7 +3991,7 @@ function drupal_render(&$elements) { // which allows the output'ed text to be filtered. if (isset($elements['#post_render'])) { foreach ($elements['#post_render'] as $function) { - if (function_exists($function)) { + if (drupal_function_exists($function)) { $elements['#children'] = $function($elements['#children'], $elements); } } @@ -4119,7 +4120,6 @@ function element_info($type) { if (!isset($cache)) { $basic_defaults = element_basic_defaults(); $cache = array(); - foreach (module_implements('elements') as $module) { $elements = module_invoke($module, 'elements'); if (isset($elements) && is_array($elements)) { @@ -5055,32 +5055,3 @@ function drupal_check_incompatibility($v, $current_version) { } } } - -/** - * Performs one or more XML-RPC request(s). - * - * @param $url - * An absolute URL of the XML-RPC endpoint. - * Example: - * http://www.example.com/xmlrpc.php - * @param ... - * For one request: - * The method name followed by a variable number of arguments to the method. - * For multiple requests (system.multicall): - * An array of call arrays. Each call array follows the pattern of the single - * request: method name followed by the arguments to the method. - * @return - * For one request: - * Either the return value of the method on success, or FALSE. - * If FALSE is returned, see xmlrpc_errno() and xmlrpc_error_msg(). - * For multiple requests: - * An array of results. Each result will either be the result - * returned by the method called, or an xmlrpc_error object if the call - * failed. See xmlrpc_error(). - */ -function xmlrpc($url) { - require_once DRUPAL_ROOT . '/includes/xmlrpc.inc'; - $args = func_get_args(); - return call_user_func_array('_xmlrpc', $args); -} - diff --git a/includes/file.inc b/includes/file.inc index 8047033be..c0e68f52e 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -320,7 +320,7 @@ function file_create_url($uri) { return FALSE; } } - + // @todo Implement CDN integration hook stuff in this function. // @see http://drupal.org/node/499156 } @@ -1250,7 +1250,7 @@ function file_validate(&$file, $validators = array()) { // Call the validation functions specified by this function's caller. $errors = array(); foreach ($validators as $function => $args) { - if (function_exists($function)) { + if (drupal_function_exists($function)) { array_unshift($args, $file); $errors = array_merge($errors, call_user_func_array($function, $args)); } diff --git a/includes/form.inc b/includes/form.inc index f36da73ab..bfacdad99 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -418,7 +418,7 @@ function drupal_retrieve_form($form_id, &$form_state) { // We first check to see if there's a function named after the $form_id. // If there is, we simply pass the arguments on to it to get the form. - if (!function_exists($form_id)) { + if (!drupal_function_exists($form_id)) { // In cases where many form_ids need to share a central constructor function, // such as the node editing form, modules can implement hook_forms(). It // maps one or more form_ids to the correct constructor functions. @@ -439,6 +439,7 @@ function drupal_retrieve_form($form_id, &$form_state) { } if (isset($form_definition['callback'])) { $callback = $form_definition['callback']; + drupal_function_exists($callback); } } @@ -612,13 +613,13 @@ function drupal_prepare_form($form_id, &$form, &$form_state) { $form += array('#tree' => FALSE, '#parents' => array()); if (!isset($form['#validate'])) { - if (function_exists($form_id . '_validate')) { + if (drupal_function_exists($form_id . '_validate')) { $form['#validate'] = array($form_id . '_validate'); } } if (!isset($form['#submit'])) { - if (function_exists($form_id . '_submit')) { + if (drupal_function_exists($form_id . '_submit')) { // We set submit here so that it can be altered. $form['#submit'] = array($form_id . '_submit'); } @@ -793,7 +794,7 @@ function _form_validate($elements, &$form_state, $form_id = NULL) { // #value data. elseif (isset($elements['#element_validate'])) { foreach ($elements['#element_validate'] as $function) { - if (function_exists($function)) { + if (drupal_function_exists($function)) { $function($elements, $form_state, $form_state['complete form']); } } @@ -830,7 +831,7 @@ function form_execute_handlers($type, &$form, &$form_state) { } foreach ($handlers as $function) { - if (function_exists($function)) { + if (drupal_function_exists($function)) { // Check to see if a previous _submit handler has set a batch, but // make sure we do not react to a batch that is already being processed // (for instance if a batch operation performs a drupal_form_submit()). @@ -969,7 +970,7 @@ function form_builder($form_id, $element, &$form_state) { // checkboxes and files. if (isset($element['#process']) && !$element['#processed']) { foreach ($element['#process'] as $process) { - if (function_exists($process)) { + if (drupal_function_exists($process)) { $element = $process($element, $form_state, $form_state['complete form']); } } @@ -1096,7 +1097,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) { // If we have input for the current element, assign it to the #value property. if (!$form_state['programmed'] || isset($input)) { // Call #type_value to set the form value; - if (function_exists($value_callback)) { + if (drupal_function_exists($value_callback)) { $element['#value'] = $value_callback($element, $input, $form_state); } if (!isset($element['#value']) && isset($input)) { @@ -1111,7 +1112,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) { // Load defaults. if (!isset($element['#value'])) { // Call #type_value without a second argument to request default_value handling. - if (function_exists($value_callback)) { + if (drupal_function_exists($value_callback)) { $element['#value'] = $value_callback($element, FALSE, $form_state); } // Final catch. If we haven't set a value yet, use the explicit default value. diff --git a/includes/image.inc b/includes/image.inc index dfc1d3002..e7734463d 100644 --- a/includes/image.inc +++ b/includes/image.inc @@ -65,7 +65,7 @@ function image_get_toolkit() { if (!isset($toolkit)) { $toolkits = image_get_available_toolkits(); $toolkit = variable_get('image_toolkit', 'gd'); - if (!isset($toolkits[$toolkit]) || !function_exists('image_' . $toolkit . '_load')) { + if (!isset($toolkits[$toolkit]) || !drupal_function_exists('image_' . $toolkit . '_load')) { // The selected toolkit isn't available so return the first one found. If // none are available this will return FALSE. reset($toolkits); @@ -90,7 +90,7 @@ function image_get_toolkit() { */ function image_toolkit_invoke($method, stdClass $image, array $params = array()) { $function = 'image_' . $image->toolkit . '_' . $method; - if (function_exists($function)) { + if (drupal_function_exists($function)) { array_unshift($params, $image); return call_user_func_array($function, $params); } diff --git a/includes/install.inc b/includes/install.inc index f66291bfb..60164b118 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -632,16 +632,15 @@ function drupal_install_system() { $system_versions = drupal_get_schema_versions('system'); $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; db_insert('system') - ->fields(array('filename', 'name', 'type', 'owner', 'status', 'schema_version', 'bootstrap')) + ->fields(array('filename', 'name', 'type', 'owner', 'status', 'schema_version')) ->values(array( 'filename' => $system_path . '/system.module', 'name' => 'system', 'type' => 'module', 'owner' => '', 'status' => 1, - 'schema_version' => $system_version, - 'bootstrap' => 0, - )) + 'schema_version' => $system_version + )) ->execute(); // Now that we've installed things properly, bootstrap the full Drupal environment drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); diff --git a/includes/mail.inc b/includes/mail.inc index e2dbd15f6..58607c1e8 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -115,7 +115,7 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N // Build the e-mail (get subject and body, allow additional headers) by // invoking hook_mail() on this module. We cannot use module_invoke() as // we need to have $message by reference in hook_mail(). - if (function_exists($function = $module . '_mail')) { + if (drupal_function_exists($function = $module . '_mail')) { $function($key, $message, $params); } diff --git a/includes/menu.inc b/includes/menu.inc index c79b0f5ca..f80836cc7 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -411,10 +411,9 @@ function menu_execute_active_handler($path = NULL) { } if ($router_item = menu_get_item($path)) { if ($router_item['access']) { - if ($router_item['file']) { - require_once($router_item['file']); + if (drupal_function_exists($router_item['page_callback'])) { + return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); } - return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); } else { return MENU_ACCESS_DENIED; @@ -517,7 +516,7 @@ function _menu_check_access(&$item, $map) { if ($callback == 'user_access') { $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]); } - elseif (function_exists($callback)) { + elseif (drupal_function_exists($callback)) { $item['access'] = call_user_func_array($callback, $arguments); } } @@ -568,7 +567,7 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) { $item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map)); } } - elseif ($callback && function_exists($callback)) { + elseif ($callback && drupal_function_exists($callback)) { if (empty($item['title_arguments'])) { $item['title'] = $callback($item['title']); } @@ -1906,7 +1905,7 @@ function menu_cache_clear_all() { function menu_rebuild() { if (!lock_acquire('menu_rebuild')) { // Wait for another request that is already doing this work. - // We choose to block here since otherwise the router item may not + // We choose to block here since otherwise the router item may not // be available in menu_execute_active_handler() resulting in a 404. lock_wait('menu_rebuild'); return FALSE; @@ -2607,12 +2606,12 @@ function _menu_router_build($callbacks) { $load_functions[$k] = NULL; } else { - if (function_exists($matches[1] . '_to_arg')) { + if (drupal_function_exists($matches[1] . '_to_arg')) { $to_arg_functions[$k] = $matches[1] . '_to_arg'; $load_functions[$k] = NULL; $match = TRUE; } - if (function_exists($matches[1] . '_load')) { + if (drupal_function_exists($matches[1] . '_load')) { $function = $matches[1] . '_load'; // Create an array of arguments that will be passed to the _load // function when this menu path is checked, if 'load arguments' @@ -2698,12 +2697,6 @@ function _menu_router_build($callbacks) { if (!isset($item['page arguments']) && isset($parent['page arguments'])) { $item['page arguments'] = $parent['page arguments']; } - if (!isset($item['file']) && isset($parent['file'])) { - $item['file'] = $parent['file']; - } - if (!isset($item['file path']) && isset($parent['file path'])) { - $item['file path'] = $parent['file path']; - } } } } @@ -2731,17 +2724,7 @@ function _menu_router_build($callbacks) { 'tab_parent' => '', 'tab_root' => $path, 'path' => $path, - 'file' => '', - 'file path' => '', - 'include file' => '', - 'module' => '', ); - - // Calculate out the file to be included for each callback, if any. - if ($item['file']) { - $file_path = $item['file path'] ? $item['file path'] : drupal_get_path('module', $item['module']); - $item['include file'] = $file_path . '/' . $item['file']; - } } // Sort the masks so they are in order of descending fit. @@ -2780,7 +2763,6 @@ function _menu_router_save($menu, $masks) { 'description', 'position', 'weight', - 'file', )); foreach ($menu as $path => $item) { @@ -2805,7 +2787,6 @@ function _menu_router_save($menu, $masks) { 'description' => $item['description'], 'position' => $item['position'], 'weight' => $item['weight'], - 'file' => $item['include file'], )); } // Execute insert object. diff --git a/includes/module.inc b/includes/module.inc index 3a5609a00..0c3f9202d 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -6,15 +6,24 @@ * API for loading and interacting with Drupal modules. */ +/** + * Pass this to module_implements when its cache needs to be written. + */ +define('MODULE_IMPLEMENTS_WRITE_CACHE', -1); + +/** + * Pass this to module_implements when its cache needs to be cleared. + */ +define('MODULE_IMPLEMENTS_CLEAR_CACHE', -2); + /** * Load all the modules that have been enabled in the system table. */ -function module_load_all($bootstrap = FALSE) { - foreach (module_list(TRUE, $bootstrap) as $module) { +function module_load_all() { + foreach (module_list(TRUE) as $module) { drupal_load('module', $module); } - module_implements('', FALSE, TRUE); } /** @@ -24,9 +33,6 @@ function module_load_all($bootstrap = FALSE) { * @param $refresh * Whether to force the module list to be regenerated (such as after the * administrator has changed the system settings). - * @param $bootstrap - * Whether to return the reduced set of modules loaded in "bootstrap mode" - * for cached pages. See bootstrap.inc. * @param $sort * By default, modules are ordered by weight and module name. Set this option * to TRUE to return a module list ordered only by module name. @@ -37,7 +43,7 @@ function module_load_all($bootstrap = FALSE) { * An associative array whose keys and values are the names of all loaded * modules. */ -function module_list($refresh = FALSE, $bootstrap = FALSE, $sort = FALSE, $fixed_list = NULL) { +function module_list($refresh = FALSE, $sort = FALSE, $fixed_list = NULL) { static $list = array(), $sorted_list; if (empty($list) || $refresh || $fixed_list) { @@ -55,12 +61,7 @@ function module_list($refresh = FALSE, $bootstrap = FALSE, $sort = FALSE, $fixed // Drupal installations, which might have modules installed in different // locations in the file system. The ordering here must also be // consistent with the one used in module_implements(). - if ($bootstrap) { - $result = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, name ASC"); - } - else { - $result = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, name ASC"); - } + $result = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, name ASC"); foreach ($result as $module) { if (file_exists($module->filename)) { drupal_get_filename('module', $module->name, $module->filename); @@ -163,7 +164,7 @@ function module_load_include($type, $module, $name = NULL) { $name = $module; } - if (function_exists('drupal_get_path')) { + if (drupal_function_exists('drupal_get_path')) { $file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type"; if (is_file($file)) { require_once $file; @@ -217,9 +218,8 @@ function module_enable($module_list, $disable_modules_installed_hook = FALSE) { } if (!empty($invoke_modules)) { - // Refresh the module list to exclude the disabled modules. + // Refresh the module list to include the new enabled module. module_list(TRUE); - module_implements('', FALSE, TRUE); // Force to regenerate the stored list of hook implementations. registry_rebuild(); @@ -235,7 +235,7 @@ function module_enable($module_list, $disable_modules_installed_hook = FALSE) { // We check for the existence of node_access_needs_rebuild() since // at install time, module_enable() could be called while node.module // is not enabled yet. - if (function_exists('node_access_needs_rebuild') && !node_access_needs_rebuild() && module_hook($module, 'node_grants')) { + if (drupal_function_exists('node_access_needs_rebuild') && !node_access_needs_rebuild() && module_hook($module, 'node_grants')) { node_access_needs_rebuild(TRUE); } } @@ -275,12 +275,11 @@ function module_disable($module_list) { } if (!empty($invoke_modules)) { - // Refresh the module list to exclude the disabled modules. - module_list(TRUE); - module_implements('', FALSE, TRUE); // Invoke hook_module_disable before disabling modules, // so we can still call module hooks to get information. module_invoke_all('modules_disabled', $invoke_modules); + // Refresh the module list to exclude the disabled modules. + module_list(TRUE); // Force to regenerate the stored list of hook implementations. registry_rebuild(); } @@ -325,49 +324,119 @@ function module_disable($module_list) { * implemented in that module. */ function module_hook($module, $hook) { - return function_exists($module . '_' . $hook); + $function = $module . '_' . $hook; + return function_exists($function) || drupal_function_exists($function); } /** * Determine which modules are implementing a hook. * * @param $hook - * The name of the hook (e.g. "help" or "menu"). - * @param $sort - * By default, modules are ordered by weight and filename, settings this option - * to TRUE, module list will be ordered by module name. - * @param $refresh - * For internal use only: Whether to force the stored list of hook + * The name of the hook (e.g. "help" or "menu"). Special cases: + * MODULE_IMPLEMENTS_CLEAR_CACHE: Force the stored list of hook * implementations to be regenerated (such as after enabling a new module, - * before processing hook_enable). + * before processing hook_enable). + * MODULE_IMPLEMENTS_WRITE_CACHE: Write the stored list of hook + * implementations into the cache_registry table. + * @param $sort + * By default, modules are ordered by weight and module name. By setting this + * option to TRUE, modules will be ordered by module name. * @return * An array with the names of the modules which are implementing this hook. + * All enabled modules are taken into consideration and the files containing + * the implementations are loaded as necessary. */ -function module_implements($hook, $sort = FALSE, $refresh = FALSE) { - static $implementations; +function module_implements($hook, $sort = FALSE) { + static $implementations = array(), $sorted_implementations = array(), $loaded = array(), $cached_hooks = 0, $maintenance; + + // Use a static variable for maintenance mode to avoid the overhead of + // calling defined() each time the function is called. + if (!isset($maintenance)) { + $maintenance = defined('MAINTENANCE_MODE'); + } - if ($refresh) { + if ($maintenance) { + return _module_implements_maintenance($hook, $sort); + } + if ($hook === MODULE_IMPLEMENTS_CLEAR_CACHE) { $implementations = array(); + $sorted_implementations = array(); + $loaded = array(); + $cached_hooks = 0; + cache_clear_all('hooks', 'cache_registry'); + return; + } + if ($hook === MODULE_IMPLEMENTS_WRITE_CACHE) { + // Only write this to cache if we loaded new implementations. + if (count($implementations) > $cached_hooks) { + cache_set('hooks', $implementations, 'cache_registry'); + } return; } - if (!isset($implementations[$hook])) { - $implementations[$hook] = array(); - $list = module_list(FALSE, FALSE, $sort); - foreach ($list as $module) { - if (module_hook($module, $hook)) { - $implementations[$hook][] = $module; + if (!isset($loaded[$hook])) { + if (empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) { + $implementations = $cache->data; + $cached_hooks = count($implementations); + } + if (!isset($implementations[$hook])) { + // The module name (rather than the filename) is used as the fallback + // weighting in order to guarantee consistent behavior across different + // Drupal installations, which might have modules installed in different + // locations in the file system. The ordering here must also be + // consistent with the one used in module_list(). + $implementations[$hook] = db_query("SELECT module FROM {registry} WHERE type = 'function' AND suffix = :hook ORDER BY weight, module", array(':hook' => $hook))->fetchCol(); + } + foreach ($implementations[$hook] as $module) { + $function = $module . '_' . $hook; + if (!function_exists($function)) { + drupal_function_exists($function); } } + $loaded[$hook] = TRUE; } - // The explicit cast forces a copy to be made. This is needed because - // $implementations[$hook] is only a reference to an element of - // $implementations and if there are nested foreaches (due to nested node - // API calls, for example), they would both manipulate the same array's - // references, which causes some modules' hooks not to be called. - // See also http://www.zend.com/zend/art/ref-count.php. - return (array)$implementations[$hook]; + if ($sort) { + if (!isset($sorted_implementations[$hook])) { + $sorted_implementations[$hook] = $implementations[$hook]; + sort($sorted_implementations[$hook]); + } + return $sorted_implementations[$hook]; + } + else { + return $implementations[$hook]; + } +} + +/** + * This is the maintenance version of module_implements for internal use only. + * + * This function is called whenever MAINTENANCE_MODE is defined and is a + * safe code path for Drupal installation or upgrade because it does not use + * the database, instead it uses module_list. @see module_list $fixed_list on + * how to make module_list also DB independent. + * + * @param $hook + * The name of the hook (e.g. "help" or "menu"). + * @param $sort + * By default, modules are ordered by weight and filename, settings this + * option to TRUE, module list will be ordered by module name. + * @return + * An array with the names of the modules which are implementing this hook. + * Only enabled and already loaded modules are taken into consideration. + */ +function _module_implements_maintenance($hook, $sort = FALSE) { + $implementations = array(); + foreach (module_list() as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $implementations[] = $module; + } + if ($sort) { + sort($implementations); + } + } + return $implementations; } /** @@ -409,7 +478,7 @@ function module_invoke_all() { $return = array(); foreach (module_implements($hook) as $module) { $function = $module . '_' . $hook; - if (function_exists($function)) { + if (drupal_function_exists($function)) { $result = call_user_func_array($function, $args); if (isset($result) && is_array($result)) { $return = array_merge_recursive($return, $result); diff --git a/includes/registry.inc b/includes/registry.inc index cf2c09757..117de9881 100644 --- a/includes/registry.inc +++ b/includes/registry.inc @@ -13,7 +13,7 @@ * * Drupal maintains an internal registry of all functions or classes in the * system, allowing it to lazy-load code files as needed (reducing the amount - * of code that must be parsed on each request). + * of code that must be parsed on each request). */ /** @@ -34,6 +34,9 @@ function _registry_rebuild() { require_once DRUPAL_ROOT . '/includes/database/select.inc'; require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/query.inc'; + // Reset the resources cache. + _registry_get_resource_name(); + // Get current list of modules and their files. $modules = system_get_module_data(); // Get the list of files we are going to parse. @@ -93,9 +96,9 @@ function _registry_rebuild() { $unchanged_resources[$key] = $file; } } - module_implements('', FALSE, TRUE); _registry_check_code(REGISTRY_RESET_LOOKUP_CACHE); + module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE); cache_clear_all('*', 'cache_registry', TRUE); // We have some unchanged resources, warm up the cache - no need to pay @@ -160,23 +163,123 @@ function _registry_parse_files($files) { * (optional) Weight of the module. */ function _registry_parse_file($filename, $contents, $module = '', $weight = 0) { - static $map = array(T_CLASS => 'class', T_INTERFACE => 'interface'); + $map = &drupal_static(__FUNCTION__, array(T_FUNCTION => 'function', T_CLASS => 'class', T_INTERFACE => 'interface')); // Delete registry entries for this file, so we can insert the new resources. db_delete('registry') ->condition('filename', $filename) ->execute(); - if (preg_match_all('/^\s*(?:abstract)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) { - $query = db_insert('registry')->fields(array('name', 'type', 'filename', 'module', 'weight')); - foreach ($matches[2] as $key => $name) { - $query->values(array( - 'name' => $name, - 'type' => $matches[1][$key], - 'filename' => $filename, - 'module' => $module, - 'weight' => $weight, - )); + $tokens = token_get_all($contents); + while ($token = next($tokens)) { + // Ignore all tokens except for those we are specifically saving. + if (is_array($token) && isset($map[$token[0]])) { + $type = $map[$token[0]]; + if ($resource_name = _registry_get_resource_name($tokens, $type)) { + $suffix = ''; + // Collect the part of the function name after the module name, + // so that we can query the registry for possible hook implementations. + if ($type == 'function' && !empty($module)) { + $n = strlen($module); + if (substr($resource_name, 0, $n) == $module) { + $suffix = substr($resource_name, $n + 1); + } + } + $fields = array( + 'filename' => $filename, + 'module' => $module, + 'suffix' => $suffix, + 'weight' => $weight, + ); + // Because some systems, such as cache, currently use duplicate function + // names in separate files an insert query cannot be used here as it + // would cause a key constraint violation. Instead we use a merge query. + // In practice this should not be an issue as those systems all initialize + // pre-registry and therefore are never loaded by the registry so it + // doesn't matter if those records in the registry table point to one + // filename instead of another. + // TODO: Convert this back to an insert query after all duplicate + // function names have been purged from Drupal. + db_merge('registry') + ->key(array('name' => $resource_name, 'type' => $type)) + ->fields($fields) + ->execute(); + + // We skip the body because classes may contain functions. + _registry_skip_body($tokens); + } + } + } +} + +/** + * Derive the name of the next resource in the token stream. + * + * When called without arguments, it resets its static cache. + * + * @param $tokens + * The collection of tokens for the current file being parsed. + * @param $type + * The human-readable token name, either: "function", "class", or "interface". + * @return + * The name of the resource, or FALSE if the resource has already been processed. + */ +function _registry_get_resource_name(&$tokens = NULL, $type = NULL) { + // Keep a running list of all resources we've saved so far, so that we never + // save one more than once. + $resources = &drupal_static(__FUNCTION__); + + if (!isset($tokens)) { + $resources = array(); + return; + } + // Determine the name of the resource. + next($tokens); // Eat a space. + $token = next($tokens); + if ($token == '&') { + $token = next($tokens); + } + $resource_name = $token[1]; + + // Ensure that we never save it more than once. + if (isset($resources[$type][$resource_name])) { + return FALSE; + } + $resources[$type][$resource_name] = TRUE; + + return $resource_name; +} + +/** + * Skip the body of a code block, as defined by { and }. + * + * This function assumes that the body starts at the next instance + * of { from the current position. + * + * @param $tokens + */ +function _registry_skip_body(&$tokens) { + $num_braces = 1; + + $token = ''; + // Get to the first open brace. + while ($token != '{' && ($token = next($tokens))); + + // Scan through the rest of the tokens until we reach the matching + // end brace. + while ($num_braces && ($token = next($tokens))) { + // PHP is really logical to have three different tokens for { with + // inconsistent names and only one for a closing brace. + if ($token == '{' || (is_array($token) && ($token[0] == T_DOLLAR_OPEN_CURLY_BRACES || $token[0] == T_CURLY_OPEN))) { + ++$num_braces; + } + elseif ($token == '}') { + --$num_braces; + } + // Consume strings manually as workaround for a bug in PHP < 5.2.3 (see + // http://drupal.org/node/368116). + elseif ($token == '"' || $token == '`' || (is_array($token) && $token[0] == T_START_HEREDOC)) { + $stop = is_array($token) ? T_END_HEREDOC : $token; + while (($token = next($tokens)) && (is_array($token) ? $token[0] : $token) != $stop); } - $query->execute(); } } diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc index cb642d979..6841325cc 100644 --- a/includes/stream_wrappers.inc +++ b/includes/stream_wrappers.inc @@ -194,8 +194,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface static function getMimeType($uri, $mapping = NULL) { if (!isset($mapping)) { $mapping = variable_get('mime_extension_mapping', NULL); - if (!isset($mapping)) { - include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc'; + if (!isset($mapping) && drupal_function_exists('file_default_mimetype_mapping')) { // The default file map, defined in file.mimetypes.inc is quite big. // We only load it when necessary. $mapping = file_default_mimetype_mapping(); diff --git a/includes/theme.inc b/includes/theme.inc index 0ad132f10..32feb595a 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -189,7 +189,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb } } - if (function_exists($registry_callback)) { + if (drupal_function_exists($registry_callback)) { $registry_callback($theme, $base_theme, $theme_engine); } } @@ -322,6 +322,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { if (function_exists($function)) { $result = $function($cache, $type, $theme, $path); + foreach ($result as $hook => $info) { $result[$hook]['type'] = $type; $result[$hook]['theme path'] = $path; @@ -335,14 +336,12 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { // functions on behalf of core .include files. // All files are included to be safe. Conditionally included // files can prevent them from getting registered. - if (isset($cache[$hook]['includes'])) { - $result[$hook]['includes'] = $cache[$hook]['includes']; + if (isset($info['file']) && !isset($info['path'])) { + $result[$hook]['file'] = $path . '/' . $info['file']; + include_once DRUPAL_ROOT . '/' . $result[$hook]['file']; } - if (isset($info['file'])) { - $include_file = isset($info['path']) ? $info['path'] : $path; - $include_file .= '/' . $info['file']; - include_once DRUPAL_ROOT . '/' . $include_file; - $result[$hook]['includes'][] = $include_file; + elseif (isset($info['file']) && isset($info['path'])) { + include_once DRUPAL_ROOT . '/' . $info['path'] . '/' . $info['file']; } // If 'arguments' have been defined previously, carry them forward. @@ -761,10 +760,12 @@ function theme() { $theme_path = $info['theme path']; // Include a file if the theme function or variable processor is held elsewhere. - if (!empty($info['includes'])) { - foreach ($info['includes'] as $include_file) { - include_once DRUPAL_ROOT . '/' . $include_file; + if (!empty($info['file'])) { + $include_file = $info['file']; + if (isset($info['path'])) { + $include_file = $info['path'] . '/' . $include_file; } + include_once DRUPAL_ROOT . '/' . $include_file; } if (isset($info['function'])) { // The theme call is a function. @@ -803,7 +804,7 @@ function theme() { foreach (array('preprocess functions', 'process functions') as $phase) { if (!empty($info[$phase])) { foreach ($info[$phase] as $processor_function) { - if (function_exists($processor_function)) { + if (drupal_function_exists($processor_function)) { $processor_function($variables, $hook_clone); } } @@ -829,7 +830,7 @@ function theme() { $suggestions[] = $variables['theme_function']; } foreach (array_reverse($suggestions) as $suggestion) { - if (function_exists($suggestion)) { + if (drupal_function_exists($suggestion)) { $info['function'] = $suggestion; break; } @@ -841,7 +842,7 @@ function theme() { } // Call the function. - if (function_exists($info['function'])) { + if (drupal_function_exists($info['function'])) { $output = call_user_func_array($info['function'], $args); } } @@ -884,7 +885,7 @@ function theme() { foreach (array('preprocess functions', 'process functions') as $phase) { if (!empty($info[$phase])) { foreach ($info[$phase] as $processor_function) { - if (function_exists($processor_function)) { + if (drupal_function_exists($processor_function)) { call_user_func_array($processor_function, $args); } } diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc index 69e675e04..20b2f6505 100644 --- a/includes/theme.maintenance.inc +++ b/includes/theme.maintenance.inc @@ -41,7 +41,7 @@ function _drupal_maintenance_theme() { // bootstrap just enough to allow hook invocations to work. $module_list['system']['filename'] = 'modules/system/system.module'; $module_list['filter']['filename'] = 'modules/filter/filter.module'; - module_list(TRUE, FALSE, FALSE, $module_list); + module_list(TRUE, FALSE, $module_list); drupal_load('module', 'system'); drupal_load('module', 'filter'); } diff --git a/includes/token.inc b/includes/token.inc index 91325d3fb..7f786121d 100644 --- a/includes/token.inc +++ b/includes/token.inc @@ -81,14 +81,14 @@ function token_replace($text, array $data = array(), array $options = array()) { } // Optionally alter the list of replacement values. - if (!empty($options['callback']) && function_exists($options['callback'])) { + if (!empty($options['callback']) && drupal_function_exists($options['callback'])) { $function = $options['callback']; $function($replacements, $data, $options); } $tokens = array_keys($replacements); $values = array_values($replacements); - + return str_replace($tokens, $values, $text); } @@ -153,11 +153,15 @@ function token_scan($text) { function token_generate($type, array $tokens, array $data = array(), array $options = array()) { $results = array(); $options += array('sanitize' => TRUE); - _token_initialize(); - $result = module_invoke_all('tokens', $type, $tokens, $data, $options); - foreach ($result as $original => $replacement) { - $results[$original] = $replacement; + foreach (module_implements('tokens') as $module) { + $function = $module . '_tokens'; + if (drupal_function_exists($function)) { + $result = $function($type, $tokens, $data, $options); + foreach ($result as $original => $replacement) { + $results[$original] = $replacement; + } + } } return $results; @@ -227,25 +231,8 @@ function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') { function token_info() { $data = &drupal_static(__FUNCTION__); if (!isset($data)) { - _token_initialize(); $data = module_invoke_all('token_info'); drupal_alter('token_info', $data); } return $data; } - -/** - * Load modulename.tokens.inc for all enabled modules. - */ -function _token_initialize() { - $initialized = drupal_static(__FUNCTION__); - if (!$initialized) { - foreach (module_list() as $module) { - $filename = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$module.tokens.inc"; - if (file_exists($filename)) { - include_once $filename; - } - } - $initialized = TRUE; - } -} diff --git a/includes/xmlrpc.inc b/includes/xmlrpc.inc index cdf3f227d..767ca101f 100644 --- a/includes/xmlrpc.inc +++ b/includes/xmlrpc.inc @@ -438,7 +438,7 @@ function xmlrpc_base64_get_xml($xmlrpc_base64) { * returned by the method called, or an xmlrpc_error object if the call * failed. See xmlrpc_error(). */ -function _xmlrpc() { +function xmlrpc() { $args = func_get_args(); $url = array_shift($args); if (is_array($args[0])) { diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc index 76ccd8895..8588680ec 100644 --- a/includes/xmlrpcs.inc +++ b/includes/xmlrpcs.inc @@ -200,7 +200,7 @@ function xmlrpc_server_call($xmlrpc_server, $methodname, $args) { } } - if (!function_exists($method)) { + if (!drupal_function_exists($method)) { return xmlrpc_error(-32601, t('Server error. Requested function @method does not exist.', array("@method" => $method))); } // Call the mapped function |