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 .
*/
2008-10-31 02:18:22 +00:00
/**
* 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 );
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 () {
2008-11-24 10:41:40 +00:00
foreach ( module_list ( TRUE ) as $module ) {
2005-07-29 07:09:30 +00:00
drupal_load ( 'module' , $module );
}
2004-12-01 22:16:50 +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 ) .
2006-02-27 15:04:45 +00:00
* @ param $sort
2008-10-31 02:18:22 +00:00
* By default , modules are ordered by weight and filename . Set this option to
* TRUE to return a module list ordered only 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 .
*/
2008-11-24 10:41:40 +00:00
function module_list ( $refresh = FALSE , $sort = FALSE , $fixed_list = NULL ) {
2008-08-21 19:36:39 +00:00
static $list = array (), $sorted_list ;
2002-01-13 13:18:48 +00:00
2008-08-21 19:36:39 +00:00
if ( empty ( $list ) || $refresh || $fixed_list ) {
2004-11-25 06:14:59 +00:00
$list = array ();
2009-01-03 08:45:28 +00:00
$sorted_list = NULL ;
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 {
2008-11-24 10:41:40 +00:00
$result = db_query ( " SELECT name, filename FROM { system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC " );
2009-01-04 18:09:34 +00:00
foreach ( $result as $module ) {
2006-07-13 13:14:25 +00:00
if ( file_exists ( $module -> filename )) {
2008-04-16 11:35:52 +00:00
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-10-02 16:49:08 +00:00
/**
2009-01-14 12:18:37 +00:00
* Find dependencies any level deep and fill in required by information too .
2007-12-13 10:46:43 +00:00
*
* @ param $files
* The array of filesystem objects used to rebuild the cache .
2006-10-02 16:49:08 +00:00
* @ return
2009-01-14 12:18:37 +00:00
* The same array with the new keys for each module :
* - requires : An array with the keys being the modules that this module
* requires .
* - required_by : An array with the keys being the modules that will not work
* without this module .
2006-10-02 16:49:08 +00:00
*/
2007-12-13 10:46:43 +00:00
function _module_build_dependencies ( $files ) {
2009-05-24 17:39:35 +00:00
require_once DRUPAL_ROOT . '/includes/graph.inc' ;
2009-01-14 12:18:37 +00:00
$roots = $files ;
foreach ( $files as $filename => $file ) {
$graph [ $file -> name ][ 'edges' ] = array ();
if ( isset ( $file -> info [ 'dependencies' ]) && is_array ( $file -> info [ 'dependencies' ])) {
foreach ( $file -> info [ 'dependencies' ] as $dependency_name ) {
$graph [ $file -> name ][ 'edges' ][ $dependency_name ] = 1 ;
unset ( $roots [ $dependency_name ]);
2006-10-02 16:49:08 +00:00
}
}
2009-01-14 12:18:37 +00:00
}
drupal_depth_first_search ( $graph , array_keys ( $roots ));
foreach ( $graph as $module => $data ) {
2009-04-11 17:58:18 +00:00
$files [ $module ] -> required_by = isset ( $data [ 'reverse_paths' ]) ? $data [ 'reverse_paths' ] : array ();
2009-01-14 12:18:37 +00:00
$files [ $module ] -> requires = isset ( $data [ 'paths' ]) ? $data [ 'paths' ] : array ();
$files [ $module ] -> sort = $data [ 'weight' ];
}
2006-08-03 01:02:51 +00:00
return $files ;
}
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 ();
2008-05-06 12:18:54 +00:00
return isset ( $list [ $module ]);
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
2008-09-20 20:22:25 +00:00
include_once DRUPAL_ROOT . '/includes/install.inc' ;
2006-08-03 01:02:51 +00:00
2008-05-07 06:39:57 +00:00
module_load_include ( 'install' , $module );
2007-05-25 12:46:46 +00:00
}
/**
* Load a module include file .
*
* @ param $type
* The include file ' s type ( file extension ) .
* @ param $module
* The module to which the include file belongs .
* @ param $name
* Optionally , specify the file name . If not set , the module ' s name is used .
*/
function module_load_include ( $type , $module , $name = NULL ) {
if ( empty ( $name )) {
$name = $module ;
}
2008-08-21 19:36:39 +00:00
if ( drupal_function_exists ( 'drupal_get_path' )) {
2008-09-20 20:22:25 +00:00
$file = DRUPAL_ROOT . '/' . drupal_get_path ( 'module' , $module ) . " / $name . $type " ;
if ( is_file ( $file )) {
require_once $file ;
return $file ;
}
2007-05-25 12:46:46 +00:00
}
2008-09-20 20:22:25 +00:00
return FALSE ;
2007-05-25 12:46:46 +00:00
}
/**
* Load an include file for each of the modules that have been enabled in
* the system table .
*/
function module_load_all_includes ( $type , $name = NULL ) {
$modules = module_list ();
foreach ( $modules as $module ) {
module_load_include ( $type , $module , $name );
2006-08-03 01:02:51 +00:00
}
}
/**
2006-11-16 08:28:08 +00:00
* Enable a given list of modules .
2006-08-03 01:02:51 +00:00
*
2006-11-16 08:28:08 +00:00
* @ param $module_list
* An array of module names .
2006-08-03 01:02:51 +00:00
*/
2006-11-16 08:28:08 +00:00
function module_enable ( $module_list ) {
$invoke_modules = array ();
foreach ( $module_list as $module ) {
2009-01-04 18:09:34 +00:00
$existing = db_query ( " SELECT status FROM { system} WHERE type = :type AND name = :name " , array (
':type' => 'module' ,
':name' => $module ))
-> fetchObject ();
2007-08-08 07:22:03 +00:00
if ( $existing -> status == 0 ) {
2006-11-16 08:28:08 +00:00
module_load_install ( $module );
2009-01-04 18:09:34 +00:00
db_update ( 'system' )
-> fields ( array ( 'status' => 1 ))
-> condition ( 'type' , 'module' )
-> condition ( 'name' , $module )
-> execute ();
2006-11-16 08:28:08 +00:00
drupal_load ( 'module' , $module );
$invoke_modules [] = $module ;
2009-05-12 18:08:43 +00:00
watchdog ( 'system' , '%module module enabled.' , array ( '%module' => $module ), WATCHDOG_INFO );
2006-11-16 08:28:08 +00:00
}
2006-08-03 01:02:51 +00:00
}
2006-11-16 08:28:08 +00:00
if ( ! empty ( $invoke_modules )) {
// Refresh the module list to include the new enabled module.
2008-11-24 10:41:40 +00:00
module_list ( TRUE );
2006-11-16 08:28:08 +00:00
// Force to regenerate the stored list of hook implementations.
2008-08-02 19:01:02 +00:00
registry_rebuild ();
2006-11-16 08:28:08 +00:00
}
foreach ( $invoke_modules as $module ) {
module_invoke ( $module , 'enable' );
2007-09-02 14:42:30 +00:00
// Check if node_access table needs rebuilding.
2007-12-08 15:15:25 +00:00
// 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.
2008-05-06 12:18:54 +00:00
if ( drupal_function_exists ( 'node_access_needs_rebuild' ) && ! node_access_needs_rebuild () && module_hook ( $module , 'node_grants' )) {
2007-09-02 14:42:30 +00:00
node_access_needs_rebuild ( TRUE );
}
2006-08-03 01:02:51 +00:00
}
2008-10-11 22:46:22 +00:00
if ( ! empty ( $invoke_modules )) {
// Invoke the hook_module_enable after all the modules have been
// enabled.
module_invoke_all ( 'modules_enabled' , $invoke_modules );
}
2006-08-03 01:02:51 +00:00
}
/**
2006-11-27 23:15:41 +00:00
* Disable a given set of modules .
2006-08-03 01:02:51 +00:00
*
2006-11-27 23:15:41 +00:00
* @ param $module_list
* An array of module names .
2006-08-03 01:02:51 +00:00
*/
2006-11-27 23:15:41 +00:00
function module_disable ( $module_list ) {
$invoke_modules = array ();
foreach ( $module_list as $module ) {
if ( module_exists ( $module )) {
2007-09-02 14:42:30 +00:00
// Check if node_access table needs rebuilding.
if ( ! node_access_needs_rebuild () && module_hook ( $module , 'node_grants' )) {
node_access_needs_rebuild ( TRUE );
}
2006-11-27 23:15:41 +00:00
module_load_install ( $module );
module_invoke ( $module , 'disable' );
2009-01-04 18:09:34 +00:00
db_update ( 'system' )
-> fields ( array ( 'status' => 0 ))
-> condition ( 'type' , 'module' )
-> condition ( 'name' , $module )
-> execute ();
2006-11-27 23:15:41 +00:00
$invoke_modules [] = $module ;
2009-05-12 18:08:43 +00:00
watchdog ( 'system' , '%module module disabled.' , array ( '%module' => $module ), WATCHDOG_INFO );
2006-11-27 23:15:41 +00:00
}
2006-08-03 01:02:51 +00:00
}
2006-11-27 23:15:41 +00:00
if ( ! empty ( $invoke_modules )) {
2008-10-11 22:46:22 +00:00
// Invoke hook_module_disable before disabling modules,
// so we can still call module hooks to get information.
module_invoke_all ( 'modules_disabled' , $invoke_modules );
2006-11-27 23:15:41 +00:00
// Refresh the module list to exclude the disabled modules.
2008-11-24 10:41:40 +00:00
module_list ( TRUE );
2006-11-27 23:15:41 +00:00
// Force to regenerate the stored list of hook implementations.
2008-08-02 19:01:02 +00:00
registry_rebuild ();
2006-08-03 01:02:51 +00:00
}
2007-09-02 14:42:30 +00:00
2007-09-04 21:10:45 +00:00
// If there remains no more node_access module, rebuilding will be
2007-09-02 14:42:30 +00:00
// straightforward, we can do it right now.
if ( node_access_needs_rebuild () && count ( module_implements ( 'node_grants' )) == 0 ) {
node_access_rebuild ();
}
2006-08-03 01:02:51 +00:00
}
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 ) {
2008-05-06 12:18:54 +00:00
$function = $module . '_' . $hook ;
if ( defined ( 'MAINTENANCE_MODE' )) {
return function_exists ( $function );
}
else {
return drupal_function_exists ( $function );
}
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
2008-10-31 02:18:22 +00:00
* The name of the hook ( e . g . " help " or " menu " ) . Special cases :
* MODULE_IMPLEMENTS_CLEAR_CACHE : Force the stored list of hook
2006-11-27 23:15:41 +00:00
* implementations to be regenerated ( such as after enabling a new module ,
2008-10-31 02:18:22 +00:00
* before processing hook_enable ) .
* MODULE_IMPLEMENTS_WRITE_CACHE : Write the stored list of hook
* implementations into the cache_registry table .
* @ param $sort
2008-12-20 18:24:41 +00:00
* By default , modules are ordered by weight and filename . By setting this
2008-10-31 02:18:22 +00:00
* option to TRUE , modules 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 .
2008-10-31 02:18:22 +00:00
* All enabled modules are taken into consideration and the files containing
* the implementations are loaded as necessary .
2005-01-16 18:44:49 +00:00
*/
2008-10-31 02:18:22 +00:00
function module_implements ( $hook , $sort = FALSE ) {
static $implementations = array (), $sorted_implementations = array (), $loaded = array (), $cached_hooks = 0 ;
2005-01-16 18:44:49 +00:00
2008-10-31 02:18:22 +00:00
if ( defined ( 'MAINTENANCE_MODE' )) {
return _module_implements_maintenance ( $hook , $sort );
2008-08-21 19:36:39 +00:00
}
2008-10-31 02:18:22 +00:00
if ( $hook === MODULE_IMPLEMENTS_CLEAR_CACHE ) {
2007-07-18 14:10:14 +00:00
$implementations = array ();
2008-10-31 02:18:22 +00:00
$sorted_implementations = array ();
$loaded = array ();
$cached_hooks = 0 ;
cache_clear_all ( 'hooks' , 'cache_registry' );
return ;
2008-05-06 12:18:54 +00:00
}
2008-10-31 02:18:22 +00:00
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 ;
2006-11-27 23:15:41 +00:00
}
2008-10-31 02:18:22 +00:00
if ( ! isset ( $loaded [ $hook ])) {
if ( empty ( $implementations ) && ( $cache = cache_get ( 'hooks' , 'cache_registry' ))) {
$implementations = $cache -> data ;
$cached_hooks = count ( $implementations );
}
2008-08-21 19:36:39 +00:00
if ( ! isset ( $implementations [ $hook ])) {
2008-10-31 02:18:22 +00:00
$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 );
2005-01-16 18:44:49 +00:00
}
}
2008-10-31 02:18:22 +00:00
$loaded [ $hook ] = TRUE ;
}
2005-01-16 18:44:49 +00:00
2008-10-31 02:18:22 +00:00
if ( $sort ) {
if ( ! isset ( $sorted_implementations [ $hook ])) {
$sorted_implementations [ $hook ] = $implementations [ $hook ];
sort ( $sorted_implementations [ $hook ]);
}
return $sorted_implementations [ $hook ];
}
else {
2008-08-21 19:36:39 +00:00
return $implementations [ $hook ];
}
2005-01-16 18:44:49 +00:00
}
2008-10-31 02:18:22 +00:00
/**
* 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 ;
}
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 ();
2007-08-30 16:09:50 +00:00
$module = $args [ 0 ];
$hook = $args [ 1 ];
unset ( $args [ 0 ], $args [ 1 ]);
2005-03-01 20:23:35 +00:00
if ( module_hook ( $module , $hook )) {
2008-05-06 12:18:54 +00:00
return call_user_func_array ( $module . '_' . $hook , $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 ();
2007-08-30 16:09:50 +00:00
$hook = $args [ 0 ];
unset ( $args [ 0 ]);
2004-07-14 20:42:20 +00:00
$return = array ();
2005-03-01 20:23:35 +00:00
foreach ( module_implements ( $hook ) as $module ) {
2008-04-14 17:48:46 +00:00
$function = $module . '_' . $hook ;
2008-05-06 12:18:54 +00:00
if ( drupal_function_exists ( $function )) {
$result = call_user_func_array ( $function , $args );
if ( isset ( $result ) && is_array ( $result )) {
$return = array_merge_recursive ( $return , $result );
}
2008-10-12 04:30:09 +00:00
elseif ( isset ( $result )) {
2008-05-06 12:18:54 +00:00
$return [] = $result ;
}
2004-08-22 17:03:42 +00:00
}
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
*/
2007-02-04 21:20:50 +00:00
/**
* Array of modules required by core .
*/
function drupal_required_modules () {
2008-10-12 01:23:07 +00:00
$files = drupal_system_listing ( '/\.info$/' , 'modules' , 'name' , 0 );
$required = array ();
foreach ( $files as $name => $file ) {
2009-02-22 17:55:30 +00:00
$info = drupal_parse_info_file ( $file -> filepath );
2008-10-12 01:23:07 +00:00
if ( ! empty ( $info ) && ! empty ( $info [ 'required' ]) && $info [ 'required' ]) {
$required [] = $name ;
}
}
return $required ;
2007-02-04 21:20:50 +00:00
}