home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / CMS / drupal-6.0.exe / drupal-6.0 / includes / module.inc < prev    next >
Encoding:
Text File  |  2007-12-27  |  16.0 KB  |  493 lines

  1. <?php
  2. // $Id: module.inc,v 1.115 2007/12/27 12:31:05 goba Exp $
  3.  
  4. /**
  5.  * @file
  6.  * API for loading and interacting with Drupal modules.
  7.  */
  8.  
  9. /**
  10.  * Load all the modules that have been enabled in the system table.
  11.  */
  12. function module_load_all() {
  13.   foreach (module_list(TRUE, FALSE) as $module) {
  14.     drupal_load('module', $module);
  15.   }
  16. }
  17.  
  18. /**
  19.  * Call a function repeatedly with each module in turn as an argument.
  20.  */
  21. function module_iterate($function, $argument = '') {
  22.   foreach (module_list() as $name) {
  23.     $function($name, $argument);
  24.   }
  25. }
  26.  
  27. /**
  28.  * Collect a list of all loaded modules. During the bootstrap, return only
  29.  * vital modules. See bootstrap.inc
  30.  *
  31.  * @param $refresh
  32.  *   Whether to force the module list to be regenerated (such as after the
  33.  *   administrator has changed the system settings).
  34.  * @param $bootstrap
  35.  *   Whether to return the reduced set of modules loaded in "bootstrap mode"
  36.  *   for cached pages. See bootstrap.inc.
  37.  * @param $sort
  38.  *   By default, modules are ordered by weight and filename, settings this option
  39.  *   to TRUE, module list will be ordered by module name.
  40.  * @param $fixed_list
  41.  *   (Optional) Override the module list with the given modules. Stays until the
  42.  *   next call with $refresh = TRUE.
  43.  * @return
  44.  *   An associative array whose keys and values are the names of all loaded
  45.  *   modules.
  46.  */
  47. function module_list($refresh = FALSE, $bootstrap = TRUE, $sort = FALSE, $fixed_list = NULL) {
  48.   static $list, $sorted_list;
  49.  
  50.   if ($refresh || $fixed_list) {
  51.     unset($sorted_list);
  52.     $list = array();
  53.     if ($fixed_list) {
  54.       foreach ($fixed_list as $name => $module) {
  55.         drupal_get_filename('module', $name, $module['filename']);
  56.         $list[$name] = $name;
  57.       }
  58.     }
  59.     else {
  60.       if ($bootstrap) {
  61.         $result = db_query("SELECT name, filename, throttle FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC");
  62.       }
  63.       else {
  64.         $result = db_query("SELECT name, filename, throttle FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC");
  65.       }
  66.       while ($module = db_fetch_object($result)) {
  67.         if (file_exists($module->filename)) {
  68.           // Determine the current throttle status and see if the module should be
  69.           // loaded based on server load. We have to directly access the throttle
  70.           // variables, since throttle.module may not be loaded yet.
  71.           $throttle = ($module->throttle && variable_get('throttle_level', 0) > 0);
  72.           if (!$throttle) {
  73.             drupal_get_filename('module', $module->name, $module->filename);
  74.             $list[$module->name] = $module->name;
  75.           }
  76.         }
  77.       }
  78.     }
  79.   }
  80.   if ($sort) {
  81.     if (!isset($sorted_list)) {
  82.       $sorted_list = $list;
  83.       ksort($sorted_list);
  84.     }
  85.     return $sorted_list;
  86.   }
  87.   return $list;
  88. }
  89.  
  90. /**
  91.  * Rebuild the database cache of module files.
  92.  *
  93.  * @return
  94.  *   The array of filesystem objects used to rebuild the cache.
  95.  */
  96. function module_rebuild_cache() {
  97.   // Get current list of modules
  98.   $files = drupal_system_listing('\.module$', 'modules', 'name', 0);
  99.  
  100.   // Extract current files from database.
  101.   system_get_files_database($files, 'module');
  102.  
  103.   ksort($files);
  104.  
  105.   // Set defaults for module info
  106.   $defaults = array(
  107.     'dependencies' => array(),
  108.     'dependents' => array(),
  109.     'description' => '',
  110.     'version' => NULL,
  111.     'php' => DRUPAL_MINIMUM_PHP,
  112.   );
  113.  
  114.   foreach ($files as $filename => $file) {
  115.     // Look for the info file.
  116.     $file->info = drupal_parse_info_file(dirname($file->filename) .'/'. $file->name .'.info');
  117.  
  118.     // Skip modules that don't provide info.
  119.     if (empty($file->info)) {
  120.       unset($files[$filename]);
  121.       continue;
  122.     }
  123.     // Merge in defaults and save.
  124.     $files[$filename]->info = $file->info + $defaults;
  125.  
  126.     // Invoke hook_system_info_alter() to give installed modules a chance to
  127.     // modify the data in the .info files if necessary.
  128.     drupal_alter('system_info', $files[$filename]->info, $files[$filename]);
  129.  
  130.     // Log the critical hooks implemented by this module.
  131.     $bootstrap = 0;
  132.     foreach (bootstrap_hooks() as $hook) {
  133.       if (module_hook($file->name, $hook)) {
  134.         $bootstrap = 1;
  135.         break;
  136.       }
  137.     }
  138.  
  139.     // Update the contents of the system table:
  140.     if (isset($file->status) || (isset($file->old_filename) && $file->old_filename != $file->filename)) {
  141.       db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename);
  142.     }
  143.     else {
  144.       // This is a new module.
  145.       $files[$filename]->status = 0;
  146.       $files[$filename]->throttle = 0;
  147.       db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap);
  148.     }
  149.   }
  150.   $files = _module_build_dependencies($files);
  151.   return $files;
  152. }
  153.  
  154. /**
  155.  * Find dependencies any level deep and fill in dependents information too.
  156.  *
  157.  * If module A depends on B which in turn depends on C then this function will
  158.  * add C to the list of modules A depends on. This will be repeated until
  159.  * module A has a list of all modules it depends on. If it depends on itself,
  160.  * called a circular dependency, that's marked by adding a nonexistent module,
  161.  * called -circular- to this list of modules. Because this does not exist,
  162.  * it'll be impossible to switch module A on.
  163.  *
  164.  * Also we fill in a dependents array in $file->info. Using the names above,
  165.  * the dependents array of module B lists A.
  166.  *
  167.  * @param $files
  168.  *   The array of filesystem objects used to rebuild the cache.
  169.  * @return
  170.  *   The same array with dependencies and dependents added where applicable.
  171.  */
  172. function _module_build_dependencies($files) {
  173.   do {
  174.     $new_dependency = FALSE;
  175.     foreach ($files as $filename => $file) {
  176.       // We will modify this object (module A, see doxygen for module A, B, C).
  177.       $file = &$files[$filename];
  178.       if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
  179.         foreach ($file->info['dependencies'] as $dependency_name) {
  180.           // This is a nonexistent module.
  181.           if ($dependency_name == '-circular-' || !isset($files[$dependency_name])) {
  182.             continue;
  183.           }
  184.           // $dependency_name is module B (again, see doxygen).
  185.           $files[$dependency_name]->info['dependents'][$filename] = $filename;
  186.           $dependency = $files[$dependency_name];
  187.           if (isset($dependency->info['dependencies']) && is_array($dependency->info['dependencies'])) {
  188.             // Let's find possible C modules.
  189.             foreach ($dependency->info['dependencies'] as $candidate) {
  190.               if (array_search($candidate, $file->info['dependencies']) === FALSE) {
  191.                 // Is this a circular dependency?
  192.                 if ($candidate == $filename) {
  193.                   // As a module name can not contain dashes, this makes
  194.                   // impossible to switch on the module.
  195.                   $candidate = '-circular-';
  196.                   // Do not display the message or add -circular- more than once.
  197.                   if (array_search($candidate, $file->info['dependencies']) !== FALSE) {
  198.                     continue;
  199.                   }
  200.                   drupal_set_message(t('%module is part of a circular dependency. This is not supported and you will not be able to switch it on.', array('%module' => $file->info['name'])), 'error');
  201.                 }
  202.                 else {
  203.                   // We added a new dependency to module A. The next loop will
  204.                   // be able to use this as "B module" thus finding even
  205.                   // deeper dependencies.
  206.                   $new_dependency = TRUE;
  207.                 }
  208.                 $file->info['dependencies'][] = $candidate;
  209.               }
  210.             }
  211.           }
  212.         }
  213.       }
  214.       // Don't forget to break the reference.
  215.       unset($file);
  216.     }
  217.   } while ($new_dependency);
  218.   return $files;
  219. }
  220.  
  221. /**
  222.  * Determine whether a given module exists.
  223.  *
  224.  * @param $module
  225.  *   The name of the module (without the .module extension).
  226.  * @return
  227.  *   TRUE if the module is both installed and enabled.
  228.  */
  229. function module_exists($module) {
  230.   $list = module_list();
  231.   return array_key_exists($module, $list);
  232. }
  233.  
  234. /**
  235.  * Load a module's installation hooks.
  236.  */
  237. function module_load_install($module) {
  238.   // Make sure the installation API is available
  239.   include_once './includes/install.inc';
  240.  
  241.   module_load_include('install', $module);
  242. }
  243.  
  244. /**
  245.  * Load a module include file.
  246.  *
  247.  * @param $type
  248.  *   The include file's type (file extension).
  249.  * @param $module
  250.  *   The module to which the include file belongs.
  251.  * @param $name
  252.  *   Optionally, specify the file name. If not set, the module's name is used.
  253.  */
  254. function module_load_include($type, $module, $name = NULL) {
  255.   if (empty($name)) {
  256.     $name = $module;
  257.   }
  258.  
  259.   $file = './'. drupal_get_path('module', $module) ."/$name.$type";
  260.  
  261.   if (is_file($file)) {
  262.     require_once $file;
  263.   }
  264.   else {
  265.     return FALSE;
  266.   }
  267. }
  268.  
  269. /**
  270.  * Load an include file for each of the modules that have been enabled in
  271.  * the system table.
  272.  */
  273. function module_load_all_includes($type, $name = NULL) {
  274.   $modules = module_list();
  275.   foreach ($modules as $module) {
  276.     module_load_include($type, $module, $name);
  277.   }
  278. }
  279.  
  280. /**
  281.  * Enable a given list of modules.
  282.  *
  283.  * @param $module_list
  284.  *   An array of module names.
  285.  */
  286. function module_enable($module_list) {
  287.   $invoke_modules = array();
  288.   foreach ($module_list as $module) {
  289.     $existing = db_fetch_object(db_query("SELECT status FROM {system} WHERE type = '%s' AND name = '%s'", 'module', $module));
  290.     if ($existing->status == 0) {
  291.       module_load_install($module);
  292.       db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 1, 0, 'module', $module);
  293.       drupal_load('module', $module);
  294.       $invoke_modules[] = $module;
  295.     }
  296.   }
  297.  
  298.   if (!empty($invoke_modules)) {
  299.     // Refresh the module list to include the new enabled module.
  300.     module_list(TRUE, FALSE);
  301.     // Force to regenerate the stored list of hook implementations.
  302.     module_implements('', FALSE, TRUE);
  303.   }
  304.  
  305.   foreach ($invoke_modules as $module) {
  306.     module_invoke($module, 'enable');
  307.     // Check if node_access table needs rebuilding.
  308.     // We check for the existence of node_access_needs_rebuild() since
  309.     // at install time, module_enable() could be called while node.module
  310.     // is not enabled yet.
  311.     if (function_exists('node_access_needs_rebuild') && !node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
  312.       node_access_needs_rebuild(TRUE);
  313.     }
  314.   }
  315. }
  316.  
  317. /**
  318.  * Disable a given set of modules.
  319.  *
  320.  * @param $module_list
  321.  *   An array of module names.
  322.  */
  323. function module_disable($module_list) {
  324.   $invoke_modules = array();
  325.   foreach ($module_list as $module) {
  326.     if (module_exists($module)) {
  327.       // Check if node_access table needs rebuilding.
  328.       if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
  329.         node_access_needs_rebuild(TRUE);
  330.       }
  331.  
  332.       module_load_install($module);
  333.       module_invoke($module, 'disable');
  334.       db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 0, 0, 'module', $module);
  335.       $invoke_modules[] = $module;
  336.     }
  337.   }
  338.  
  339.   if (!empty($invoke_modules)) {
  340.     // Refresh the module list to exclude the disabled modules.
  341.     module_list(TRUE, FALSE);
  342.     // Force to regenerate the stored list of hook implementations.
  343.     module_implements('', FALSE, TRUE);
  344.   }
  345.  
  346.   // If there remains no more node_access module, rebuilding will be
  347.   // straightforward, we can do it right now.
  348.   if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
  349.     node_access_rebuild();
  350.   }
  351. }
  352.  
  353. /**
  354.  * @defgroup hooks Hooks
  355.  * @{
  356.  * Allow modules to interact with the Drupal core.
  357.  *
  358.  * Drupal's module system is based on the concept of "hooks". A hook is a PHP
  359.  * function that is named foo_bar(), where "foo" is the name of the module (whose
  360.  * filename is thus foo.module) and "bar" is the name of the hook. Each hook has
  361.  * a defined set of parameters and a specified result type.
  362.  *
  363.  * To extend Drupal, a module need simply implement a hook. When Drupal wishes to
  364.  * allow intervention from modules, it determines which modules implement a hook
  365.  * and call that hook in all enabled modules that implement it.
  366.  *
  367.  * The available hooks to implement are explained here in the Hooks section of
  368.  * the developer documentation. The string "hook" is used as a placeholder for
  369.  * the module name is the hook definitions. For example, if the module file is
  370.  * called example.module, then hook_help() as implemented by that module would be
  371.  * defined as example_help().
  372.  */
  373.  
  374. /**
  375.  * Determine whether a module implements a hook.
  376.  *
  377.  * @param $module
  378.  *   The name of the module (without the .module extension).
  379.  * @param $hook
  380.  *   The name of the hook (e.g. "help" or "menu").
  381.  * @return
  382.  *   TRUE if the module is both installed and enabled, and the hook is
  383.  *   implemented in that module.
  384.  */
  385. function module_hook($module, $hook) {
  386.   return function_exists($module .'_'. $hook);
  387. }
  388.  
  389. /**
  390.  * Determine which modules are implementing a hook.
  391.  *
  392.  * @param $hook
  393.  *   The name of the hook (e.g. "help" or "menu").
  394.  * @param $sort
  395.  *   By default, modules are ordered by weight and filename, settings this option
  396.  *   to TRUE, module list will be ordered by module name.
  397.  * @param $refresh
  398.  *   For internal use only: Whether to force the stored list of hook
  399.  *   implementations to be regenerated (such as after enabling a new module,
  400.  *   before processing hook_enable).
  401.  * @return
  402.  *   An array with the names of the modules which are implementing this hook.
  403.  */
  404. function module_implements($hook, $sort = FALSE, $refresh = FALSE) {
  405.   static $implementations;
  406.  
  407.   if ($refresh) {
  408.     $implementations = array();
  409.     return;
  410.   }
  411.  
  412.   if (!isset($implementations[$hook])) {
  413.     $implementations[$hook] = array();
  414.     $list = module_list(FALSE, TRUE, $sort);
  415.     foreach ($list as $module) {
  416.       if (module_hook($module, $hook)) {
  417.         $implementations[$hook][] = $module;
  418.       }
  419.     }
  420.   }
  421.  
  422.   // The explicit cast forces a copy to be made. This is needed because
  423.   // $implementations[$hook] is only a reference to an element of
  424.   // $implementations and if there are nested foreaches (due to nested node
  425.   // API calls, for example), they would both manipulate the same array's
  426.   // references, which causes some modules' hooks not to be called.
  427.   // See also http://www.zend.com/zend/art/ref-count.php.
  428.   return (array)$implementations[$hook];
  429. }
  430.  
  431. /**
  432.  * Invoke a hook in a particular module.
  433.  *
  434.  * @param $module
  435.  *   The name of the module (without the .module extension).
  436.  * @param $hook
  437.  *   The name of the hook to invoke.
  438.  * @param ...
  439.  *   Arguments to pass to the hook implementation.
  440.  * @return
  441.  *   The return value of the hook implementation.
  442.  */
  443. function module_invoke() {
  444.   $args = func_get_args();
  445.   $module = $args[0];
  446.   $hook = $args[1];
  447.   unset($args[0], $args[1]);
  448.   $function = $module .'_'. $hook;
  449.   if (module_hook($module, $hook)) {
  450.     return call_user_func_array($function, $args);
  451.   }
  452. }
  453. /**
  454.  * Invoke a hook in all enabled modules that implement it.
  455.  *
  456.  * @param $hook
  457.  *   The name of the hook to invoke.
  458.  * @param ...
  459.  *   Arguments to pass to the hook.
  460.  * @return
  461.  *   An array of return values of the hook implementations. If modules return
  462.  *   arrays from their implementations, those are merged into one array.
  463.  */
  464. function module_invoke_all() {
  465.   $args = func_get_args();
  466.   $hook = $args[0];
  467.   unset($args[0]);
  468.   $return = array();
  469.   foreach (module_implements($hook) as $module) {
  470.     $function = $module .'_'. $hook;
  471.     $result = call_user_func_array($function, $args);
  472.     if (isset($result) && is_array($result)) {
  473.       $return = array_merge_recursive($return, $result);
  474.     }
  475.     else if (isset($result)) {
  476.       $return[] = $result;
  477.     }
  478.   }
  479.  
  480.   return $return;
  481. }
  482.  
  483. /**
  484.  * @} End of "defgroup hooks".
  485.  */
  486.  
  487. /**
  488.  * Array of modules required by core.
  489.  */
  490. function drupal_required_modules() {
  491.   return array('block', 'filter', 'node', 'system', 'user');
  492. }
  493.