2002-01-13 13:18:48 +00:00
< ? php
// $Id$
2004-07-22 16:06:54 +00:00
/**
* @ file
* API for loading and interacting with Drupal modules .
*/
2004-12-01 22:16:50 +00:00
/**
2006-06-08 21:23:40 +00:00
* Load all the modules that have been enabled in the system table .
2004-12-01 22:16:50 +00:00
*/
2006-06-08 21:23:40 +00:00
function module_load_all () {
2005-07-29 07:09:30 +00:00
foreach ( module_list ( TRUE , FALSE ) as $module ) {
drupal_load ( 'module' , $module );
}
2004-12-01 22:16:50 +00:00
}
2004-07-14 20:42:20 +00:00
/**
* Call a function repeatedly with each module in turn as an argument .
*/
function module_iterate ( $function , $argument = '' ) {
2002-10-17 18:34:38 +00:00
foreach ( module_list () as $name ) {
$function ( $name , $argument );
}
2002-01-13 13:18:48 +00:00
}
2004-07-14 20:42:20 +00:00
/**
2005-04-03 08:03:18 +00:00
* Collect a list of all loaded modules . During the bootstrap , return only
* vital modules . See bootstrap . inc
2004-07-14 20:42:20 +00:00
*
* @ param $refresh
* Whether to force the module list to be regenerated ( such as after the
* administrator has changed the system settings ) .
* @ param $bootstrap
2005-04-03 08:03:18 +00:00
* Whether to return the reduced set of modules loaded in " bootstrap mode "
* for cached pages . See bootstrap . inc .
2006-02-27 15:04:45 +00:00
* @ param $sort
* By default , modules are ordered by weight and filename , settings this option
* to TRUE , module list will be ordered by module name .
2006-07-13 13:14:25 +00:00
* @ param $fixed_list
* ( Optional ) Override the module list with the given modules . Stays until the
* next call with $refresh = TRUE .
2004-07-14 20:42:20 +00:00
* @ return
* An associative array whose keys and values are the names of all loaded
* modules .
*/
2006-07-13 13:14:25 +00:00
function module_list ( $refresh = FALSE , $bootstrap = TRUE , $sort = FALSE , $fixed_list = NULL ) {
2006-02-27 15:04:45 +00:00
static $list , $sorted_list ;
2002-01-13 13:18:48 +00:00
2006-07-13 13:14:25 +00:00
if ( $refresh || $fixed_list ) {
2006-06-28 21:18:30 +00:00
unset ( $sorted_list );
2004-11-25 06:14:59 +00:00
$list = array ();
2006-07-13 13:14:25 +00:00
if ( $fixed_list ) {
foreach ( $fixed_list as $name => $module ) {
drupal_get_filename ( 'module' , $name , $module [ 'filename' ]);
$list [ $name ] = $name ;
}
2004-01-26 18:55:43 +00:00
}
else {
2006-07-13 13:14:25 +00:00
if ( $bootstrap ) {
$result = db_query ( " SELECT name, filename, throttle, bootstrap FROM { system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC " );
}
else {
$result = db_query ( " SELECT name, filename, throttle, bootstrap FROM { system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC " );
}
while ( $module = db_fetch_object ( $result )) {
if ( file_exists ( $module -> filename )) {
// Determine the current throttle status and see if the module should be
// loaded based on server load. We have to directly access the throttle
// variables, since throttle.module may not be loaded yet.
$throttle = ( $module -> throttle && variable_get ( 'throttle_level' , 0 ) > 0 );
if ( ! $throttle ) {
drupal_get_filename ( 'module' , $module -> name , $module -> filename );
$list [ $module -> name ] = $module -> name ;
}
2003-11-18 19:44:36 +00:00
}
2002-06-01 21:57:29 +00:00
}
2002-01-13 13:18:48 +00:00
}
}
2006-02-27 15:04:45 +00:00
if ( $sort ) {
if ( ! isset ( $sorted_list )) {
$sorted_list = $list ;
ksort ( $sorted_list );
}
return $sorted_list ;
}
2002-01-13 13:18:48 +00:00
return $list ;
}
2006-08-03 01:02:51 +00:00
/**
* Rebuild the database cache of module files .
2006-08-03 07:06:36 +00:00
*
2006-08-03 01:02:51 +00:00
* @ return
* The array of filesystem objects used to rebuild the cache .
*/
function module_rebuild_cache () {
// Get current list of modules
$files = system_listing ( '\.module$' , 'modules' , 'name' , 0 );
// Extract current files from database.
system_get_files_database ( $files , 'module' );
ksort ( $files );
foreach ( $files as $filename => $file ) {
2006-08-31 20:22:37 +00:00
$file -> info = _module_parse_info_file ( dirname ( $file -> filename ) . '/' . $file -> name . '.info' );
// Skip modules that don't provide info.
if ( empty ( $file -> info )) {
unset ( $files [ $filename ]);
continue ;
}
$files [ $filename ] -> info = $file -> info ;
2006-08-03 01:02:51 +00:00
// log the critical hooks implemented by this module
$bootstrap = 0 ;
foreach ( bootstrap_hooks () as $hook ) {
if ( module_hook ( $file -> name , $hook )) {
$bootstrap = 1 ;
break ;
}
}
// Update the contents of the system table:
2006-08-31 20:22:37 +00:00
// TODO: We shouldn't actually need this description field anymore. Remove me next release.
2006-08-03 01:02:51 +00:00
if ( isset ( $file -> status ) || ( isset ( $file -> old_filename ) && $file -> old_filename != $file -> filename )) {
2006-08-31 20:22:37 +00:00
db_query ( " UPDATE { system} SET description = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s' " , $file -> info [ 'description' ], $file -> name , $file -> filename , $bootstrap , $file -> old_filename );
2006-08-03 01:02:51 +00:00
}
else {
// This is a new module.
2006-08-31 20:22:37 +00:00
db_query ( " INSERT INTO { system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d) " , $file -> name , $file -> info [ 'description' ], 'module' , $file -> filename , $file -> status , $file -> throttle , $bootstrap );
2006-08-03 01:02:51 +00:00
}
}
return $files ;
}
2006-08-31 20:22:37 +00:00
/**
* Parse Drupal info file format .
* Uses ini parser provided by php ' s parse_ini_file () .
*
* Files should use the ini format to specify values .
* e . g .
* key = " value "
* key2 = value2
*
* Some things to be aware of :
* - This function is NOT for placing arbitrary module - specific settings . Use variable_get ()
* and variable_set () for that .
* - You may not use double - quotes in a value .
*
* @ param $filename
* The file we are parsing . Accepts file with relative or absolute path .
* @ return
* The info array .
*/
function _module_parse_info_file ( $filename ) {
$info = array ();
if ( file_exists ( $filename )) {
$info = parse_ini_file ( $filename );
}
return $info ;
}
2004-07-14 20:42:20 +00:00
/**
* Determine whether a given module exists .
*
* @ param $module
* The name of the module ( without the . module extension ) .
* @ return
* TRUE if the module is both installed and enabled .
*/
2006-08-20 05:57:41 +00:00
function module_exists ( $module ) {
2002-01-13 13:18:48 +00:00
$list = module_list ();
2004-07-14 20:42:20 +00:00
return array_key_exists ( $module , $list );
2002-01-13 13:18:48 +00:00
}
2006-08-03 01:02:51 +00:00
/**
* Load a module ' s installation hooks .
*/
function module_load_install ( $module ) {
// Make sure the installation API is available
include_once './includes/install.inc' ;
$install_file = './' . drupal_get_path ( 'module' , $module ) . '/' . $module . '.install' ;
if ( is_file ( $install_file )) {
include_once $install_file ;
}
}
/**
* Enable a given module .
*
* @ param $module
* Enable a given module and call its enable hook .
*/
function module_enable ( $module ) {
$existing = db_fetch_object ( db_query ( " SELECT name, status FROM { system} WHERE type = 'module' AND name = '%s' " , $module ));
if ( $existing -> status === '0' ) {
module_load_install ( $module );
db_query ( " UPDATE { system} SET status = 1, throttle = 0 WHERE type = 'module' AND name = '%s' " , $module );
drupal_load ( 'module' , $module );
module_invoke ( $module , 'enable' );
return TRUE ;
}
else {
return FALSE ;
}
}
/**
* Disable a given module and call its disable hook .
*
* @ param $module
* The name of the module ( without the . module extension ) .
*/
function module_disable ( $module ) {
2006-08-20 05:57:41 +00:00
if ( module_exists ( $module )) {
2006-08-03 01:02:51 +00:00
module_load_install ( $module );
module_invoke ( $module , 'disable' );
db_query ( " UPDATE { system} SET status = 0, throttle = 0 WHERE type = 'module' AND name = '%s' " , $module );
return TRUE ;
}
else {
return FALSE ;
}
}
2004-07-14 20:42:20 +00:00
/**
* @ defgroup hooks Hooks
2004-09-09 05:51:08 +00:00
* @ {
* Allow modules to interact with the Drupal core .
2004-07-14 20:42:20 +00:00
*
* Drupal ' s module system is based on the concept of " hooks " . A hook is a PHP
* function that is named foo_bar (), where " foo " is the name of the module ( whose
* filename is thus foo . module ) and " bar " is the name of the hook . Each hook has
* a defined set of parameters and a specified result type .
*
* To extend Drupal , a module need simply implement a hook . When Drupal wishes to
* allow intervention from modules , it determines which modules implement a hook
* and call that hook in all enabled modules that implement it .
*
* The available hooks to implement are explained here in the Hooks section of
* the developer documentation . The string " hook " is used as a placeholder for
* the module name is the hook definitions . For example , if the module file is
* called example . module , then hook_help () as implemented by that module would be
* defined as example_help () .
*/
/**
* Determine whether a module implements a hook .
*
* @ param $module
* The name of the module ( without the . module extension ) .
* @ param $hook
* The name of the hook ( e . g . " help " or " menu " ) .
* @ return
* TRUE if the module is both installed and enabled , and the hook is
* implemented in that module .
*/
function module_hook ( $module , $hook ) {
return function_exists ( $module . '_' . $hook );
2002-01-13 13:18:48 +00:00
}
2005-01-16 18:44:49 +00:00
/**
* Determine which modules are implementing a hook .
*
* @ param $hook
* The name of the hook ( e . g . " help " or " menu " ) .
2006-02-27 15:04:45 +00:00
* @ param $sort
* By default , modules are ordered by weight and filename , settings this option
* to TRUE , module list will be ordered by module name .
2005-01-16 18:44:49 +00:00
* @ return
* An array with the names of the modules which are implementing this hook .
*/
2006-02-27 15:04:45 +00:00
function module_implements ( $hook , $sort = FALSE ) {
2005-01-16 18:44:49 +00:00
static $implementations ;
if ( ! isset ( $implementations [ $hook ])) {
$implementations [ $hook ] = array ();
2006-02-27 15:04:45 +00:00
$list = module_list ( FALSE , TRUE , $sort );
2005-01-16 18:44:49 +00:00
foreach ( $list as $module ) {
if ( module_hook ( $module , $hook )) {
$implementations [ $hook ][] = $module ;
}
}
}
2006-05-07 00:08:36 +00:00
// The explicit cast forces a copy to be made. This is needed because
2005-12-14 18:46:21 +00:00
// $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 ];
2005-01-16 18:44:49 +00:00
}
2004-07-14 20:42:20 +00:00
/**
* Invoke a hook in a particular module .
*
* @ param $module
* The name of the module ( without the . module extension ) .
* @ param $hook
* The name of the hook to invoke .
* @ param ...
* Arguments to pass to the hook implementation .
* @ return
* The return value of the hook implementation .
*/
2005-03-01 20:23:35 +00:00
function module_invoke () {
$args = func_get_args ();
$module = array_shift ( $args );
$hook = array_shift ( $args );
2004-07-14 20:42:20 +00:00
$function = $module . '_' . $hook ;
2005-03-01 20:23:35 +00:00
if ( module_hook ( $module , $hook )) {
return call_user_func_array ( $function , $args );
2004-07-14 20:42:20 +00:00
}
}
/**
* Invoke a hook in all enabled modules that implement it .
*
* @ param $hook
* The name of the hook to invoke .
* @ param ...
* Arguments to pass to the hook .
* @ return
* An array of return values of the hook implementations . If modules return
* arrays from their implementations , those are merged into one array .
*/
2005-03-01 20:23:35 +00:00
function module_invoke_all () {
$args = func_get_args ();
$hook = array_shift ( $args );
2004-07-14 20:42:20 +00:00
$return = array ();
2005-03-01 20:23:35 +00:00
foreach ( module_implements ( $hook ) as $module ) {
$function = $module . '_' . $hook ;
$result = call_user_func_array ( $function , $args );
2005-12-14 20:10:45 +00:00
if ( isset ( $result ) && is_array ( $result )) {
2004-07-14 20:42:20 +00:00
$return = array_merge ( $return , $result );
}
2004-08-22 17:03:42 +00:00
else if ( isset ( $result )) {
$return [] = $result ;
}
2004-07-14 20:42:20 +00:00
}
return $return ;
}
/**
2004-09-09 05:51:08 +00:00
* @ } End of " defgroup hooks " .
2004-07-14 20:42:20 +00:00
*/
2005-08-25 21:14:17 +00:00