? sites/default/files ? sites/default/settings.php Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.120 diff -u -p -r1.120 module.inc --- includes/module.inc 13 May 2008 17:38:42 -0000 1.120 +++ includes/module.inc 5 Jul 2008 01:58:15 -0000 @@ -101,6 +101,7 @@ function module_rebuild_cache() { 'dependencies' => array(), 'dependents' => array(), 'description' => '', + 'package' => 'Other', 'version' => NULL, 'php' => DRUPAL_MINIMUM_PHP, ); Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.78 diff -u -p -r1.78 system.admin.inc --- modules/system/system.admin.inc 1 Jul 2008 20:36:40 -0000 1.78 +++ modules/system/system.admin.inc 5 Jul 2008 01:58:15 -0000 @@ -618,131 +618,65 @@ function system_modules($form_state = ar return system_modules_confirm_form($files, $form_state['storage']); } $dependencies = array(); - - // Store module list for validation callback. - $form['validation_modules'] = array('#type' => 'value', '#value' => $files); - - // Create storage for disabled modules as browser will disable checkboxes. - $form['disabled_modules'] = array('#type' => 'value', '#value' => array()); - - // Traverse the files, checking for compatibility - $incompatible_core = array(); - $incompatible_php = array(); - foreach ($files as $filename => $file) { - // Ensure this module is compatible with this version of core. - if (!isset($file->info['core']) || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY) { - $incompatible_core[$file->name] = $file->name; - } - // Ensure this module is compatible with the currently installed version of PHP. - if (version_compare(phpversion(), $file->info['php']) < 0) { - $incompatible_php[$file->name] = $file->info['php']; - } - } + $modules = array(); + $form['modules'] = array('#tree' => TRUE); // Used when checking if module implements a help page. $help_arg = module_exists('help') ? drupal_help_arg() : FALSE; - // Array for disabling checkboxes in callback system_module_disable. - $disabled = array(); - // Traverse the files retrieved and build the form. - foreach ($files as $filename => $file) { - $form['name'][$filename] = array('#value' => $file->info['name']); - $form['version'][$filename] = array('#value' => $file->info['version']); - $form['description'][$filename] = array('#value' => t($file->info['description'])); - // Generate link for module's help page, if there is one. - if ($help_arg && module_hook($filename, 'help')) { - if (module_invoke($filename, 'help', "admin/help#$filename", $help_arg)) { - // Module has a help page. - $form['help'][$filename] = array('#value' => theme('more_help_link', url("admin/help/$filename"))); - } - } - - $options[$filename] = ''; - // Ensure this module is compatible with this version of core and php. - if (_system_is_incompatible($incompatible_core, $files, $file) || _system_is_incompatible($incompatible_php, $files, $file)) { - $disabled[] = $file->name; - // Nothing else in this loop matters, so move to the next module. - continue; - } - if ($file->status) { - $status[] = $file->name; - } - - $dependencies = array(); - // Check for missing dependencies. - if (is_array($file->info['dependencies'])) { - foreach ($file->info['dependencies'] as $dependency) { - if (!isset($files[$dependency]) || !$files[$dependency]->status) { - if (isset($files[$dependency])) { - $dependencies[] = $files[$dependency]->info['name'] . t(' (disabled)'); - } - else { - $dependencies[] = drupal_ucfirst($dependency) . t(' (missing)'); - $disabled[] = $filename; - $form['disabled_modules']['#value'][$filename] = FALSE; - } + $modules_required = drupal_required_modules(); + foreach ($files as $filename => $module) { + $extra = array(); + if (in_array($filename, $modules_required)) { + $extra['required'] = TRUE; + } + $extra['enabled'] = (bool) $module->status; + if (is_array($module->info['dependencies'])) { + foreach ($module->info['dependencies'] as $dependency) { + if (!isset($files[$dependency])) { + $extra['dependencies'][$dependency] = drupal_ucfirst($dependency) . t(' (missing)'); + $extra['disabled'] = TRUE; + } + elseif (!$files[$dependency]->status) { + $extra['dependencies'][$dependency] = $files[$dependency]->info['name'] . t(' (disabled)'); } else { - $dependencies[] = $files[$dependency]->info['name'] . t(' (enabled)'); + $extra['dependencies'][$dependency] = $files[$dependency]->info['name'] . t(' (enabled)'); } } - - // Add text for dependencies. - if (!empty($dependencies)) { - $form['description'][$filename]['dependencies'] = array( - '#value' => t('Depends on: !dependencies', array('!dependencies' => implode(', ', $dependencies))), - '#prefix' => '
', - '#suffix' => '
', - ); + } + // Generate link for module's help page, if there is one. + if ($help_arg && module_hook($filename, 'help')) { + if (module_invoke($filename, 'help', "admin/help#$filename", $help_arg)) { + // Module has a help page. + $extra['help'] = theme('more_help_link', url("admin/help/$filename")); } } - + // Mark dependents disabled so user can not remove modules being depended on. $dependents = array(); - foreach ($file->info['dependents'] as $dependent) { + foreach ($module->info['dependents'] as $dependent) { if ($files[$dependent]->status == 1) { - $dependents[] = $files[$dependent]->info['name'] . t(' (enabled)'); - $disabled[] = $filename; - $form['disabled_modules']['#value'][$filename] = TRUE; + $extra['dependents'][] = $files[$dependent]->info['name'] . t(' (enabled)'); + $extra['disabled'] = TRUE; } else { - $dependents[] = $files[$dependent]->info['name'] . t(' (disabled)'); + $extra['dependents'][] = $files[$dependent]->info['name'] . t(' (disabled)'); } } - - // Add text for enabled dependents. - if (!empty($dependents)) { - $form['description'][$filename]['required'] = array( - '#value' => t('Required by: !required', array('!required' => implode(', ', $dependents))), - '#prefix' => '
', - '#suffix' => '
', - ); - } + $form['modules'][$module->info['package']][$filename] = _system_modules_build_module($module->info, $extra); + } + foreach (element_children($form['modules']) as $package) { + $form['modules'][$package] += array( + '#type' => 'fieldset', + '#title' => t($package), + '#collapsible' => TRUE, + '#collapsed' => ($package == 'Core - required'), + '#theme' => 'system_modules_fieldset', + ); } - $modules_required = drupal_required_modules(); - // Merge in required modules. - foreach ($modules_required as $required) { - $disabled[] = $required; - $form['disabled_modules']['#value'][$required] = TRUE; - } - - // Handle status checkboxes, including overriding - // the generated checkboxes for required modules. - $form['status'] = array( - '#type' => 'checkboxes', - '#default_value' => $status, - '#options' => $options, - '#process' => array( - 'expand_checkboxes', - 'system_modules_disable', - ), - '#disabled_modules' => $disabled, - '#incompatible_modules_core' => $incompatible_core, - '#incompatible_modules_php' => $incompatible_php, - ); - - $form['buttons']['submit'] = array( + $form['submit'] = array( '#type' => 'submit', '#value' => t('Save configuration'), ); @@ -758,20 +692,72 @@ function system_sort_modules_by_info_nam return strcasecmp($a->info['name'], $b->info['name']); } -/** - * Form process callback function to disable check boxes. - * - * @param $form - * The form structure. - * @param $edit - * Not used. - * @ingroup forms - * @return - * The form structure. - */ -function system_modules_disable($form, $edit) { - foreach ($form['#disabled_modules'] as $key) { - $form[$key]['#attributes']['disabled'] = 'disabled'; +function _system_modules_build_module($info, $extra) { + $extra += array( + 'required' => FALSE, + 'dependencies' => array(), + 'dependents' => array(), + 'disabled' => FALSE, + 'enabled' => FALSE, + 'help' => '', + ); + $form = array( + '#tree' => TRUE, + ); + $form['name'] = array( + '#value' => t($info['name']), + ); + $form['description'] = array( + '#value' => t($info['description']), + ); + $form['version'] = array( + '#value' => $info['version'], + ); + $form['#dependencies'] = $extra['dependencies']; + $form['#dependents'] = $extra['dependents']; + + $compatible = TRUE; + $status_short = ''; + $status_long = ''; + + if (!isset($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) { + $compatible = FALSE; + $status_short .= t('Incompatible with this version of Drupal core. '); + $status_long .= t('This version is incompatible with the !core_version version of Drupal core. ', array('!core_version' => VERSION)); + } + + // Ensure this module is compatible with the currently installed version of PHP. + if (version_compare(phpversion(), $info['php']) < 0) { + $compatible = FALSE; + $status_short .= t('Incompatible with this version of PHP'); + if (substr_count($info['php'], '.') < 2) { + $php_required .= '.*'; + } + $status_long .= t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $php_required, '!php_version' => phpversion())); + } + + if ($compatible) { + $form['enable'] = array( + '#type' => 'checkbox', + '#title' => t('Enable'), + '#required' => $extra['required'], + '#default_value' => $extra['enabled'], + ); + if ($extra['disabled']) { + $form['enable']['#disabled'] = TRUE; + } + } + else { + $form['enable'] = array( + '#value' => theme('image', 'misc/watchdog-error.png', t('incompatible'), $status_short), + ); + $form['description']['#value'] .= theme('system_modules_incompatible', $status_long); + } + + if ($extra['help']) { + $form['help'] = array( + '#value' => $extra['help'], + ); } return $form; } @@ -791,25 +777,14 @@ function system_modules_confirm_form($mo $form = array(); $items = array(); - list($dependencies, $status) = $storage; - $form['validation_modules'] = array('#type' => 'value', '#value' => $modules); $form['status']['#tree'] = TRUE; - // Remember list of modules selected on the module listing page already. - foreach ($status as $key => $choice) { - $form['status'][$key] = array('#type' => 'value', '#value' => $choice); - } - foreach ($dependencies as $name => $missing_dependencies) { - $form['status'][$name] = array('#type' => 'hidden', '#value' => 1); - foreach ($missing_dependencies as $k => $dependency) { - $form['status'][$dependency] = array('#type' => 'hidden', '#value' => 1); - $info = $modules[$dependency]->info; - $missing_dependencies[$k] = $info['name'] ? $info['name'] : drupal_ucfirst($dependency); - } + + foreach ($storage['dependencies'] as $info) { $t_argument = array( - '@module' => $modules[$name]->info['name'], - '@dependencies' => implode(', ', $missing_dependencies), + '@module' => $info['name'], + '@dependencies' => implode(', ', $info['dependencies']), ); - $items[] = format_plural(count($missing_dependencies), 'You must enable the @dependencies module to install @module.', 'You must enable the @dependencies modules to install @module.', $t_argument); + $items[] = format_plural(count($info['dependencies']), 'You must enable the @dependencies module to install @module.', 'You must enable the @dependencies modules to install @module.', $t_argument); } $form['text'] = array('#value' => theme('item_list', $items)); @@ -831,58 +806,71 @@ function system_modules_confirm_form($mo */ function system_modules_submit($form, &$form_state) { include_once './includes/install.inc'; - $new_modules = array(); - - // If we are coming from the confirm form... + $modules = array(); if (!isset($form_state['storage'])) { - // Merge in disabled active modules since they should be enabled. - // They don't appear because disabled checkboxes are not submitted - // by browsers. - $form_state['values']['status'] = array_merge($form_state['values']['status'], $form_state['values']['disabled_modules']); - - // Check values for dependency that we can't install. - if ($dependencies = system_module_build_dependencies($form_state['values']['validation_modules'], $form_state['values'])) { - // These are the modules that depend on existing modules. - foreach (array_keys($dependencies) as $name) { - $form_state['values']['status'][$name] = 0; + foreach ($form_state['values']['modules'] as $group_name => $group) { + foreach ($group as $module => $enabled) { + $modules[$module] = array('group' => $group_name, 'enabled' => $enabled['enable']); } } } else { - $dependencies = NULL; + $modules = $form_state['storage']['modules']; } + $files = module_rebuild_cache(); + + $enabled_modules = array(); + $disable_modules = array(); + $new_modules = array(); + $dependencies = array(); + foreach ($modules as $name => $module) { + if ($module['enabled']) { + if (drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) { + $new_modules[$name] = $name; + } + else { + $enable_modules[$name] = $name; + } + if (empty($form_state['storage'])) { + foreach ($form['modules'][$module['group']][$name]['#dependencies'] as $dependency => $string) { + if (!isset($dependencies[$name])) { + $dependencies[$name] = array( + 'name' => $files[$name]->info['name'], + 'dependencies' => array($dependency => $files[$dependency]->info['name']), + ); + } + else { + $dependencies[$name]['dependencies'][$dependency] = $files[$dependency]->info['name']; + } + $modules[$dependency] = array('group' => $files[$dependency]->info['package'], 'enabled' => TRUE); + } + } + } + else { + $disable_modules[$name] = $name; + } + } // If there where unmet dependencies and they haven't confirmed don't process // the submission yet. Store the form submission data needed later. if ($dependencies) { if (!isset($form_state['values']['confirm'])) { - $form_state['storage'] = array($dependencies, $form_state['values']['status']); + $form_state['storage'] = array('dependencies' => $dependencies, 'modules' => $modules); return; } else { - $form_state['values']['status'] = array_merge($form_state['values']['status'], $form_storage[1]); + $dependencies = $form_storage['dependencies']; + foreach ($dependencies as $info) { + foreach ($info['dependencies'] as $dependency => $name) { + $new_modules[$name] = $name; + } + } } } // If we have no dependencies, or the dependencies are confirmed // to be installed, we don't need the temporary storage anymore. unset($form_state['storage']); - $enable_modules = array(); - $disable_modules = array(); - foreach ($form_state['values']['status'] as $key => $choice) { - if ($choice) { - if (drupal_get_installed_schema_version($key) == SCHEMA_UNINSTALLED) { - $new_modules[] = $key; - } - else { - $enable_modules[] = $key; - } - } - else { - $disable_modules[] = $key; - } - } - $old_module_list = module_list(); if (!empty($enable_modules)) { @@ -893,12 +881,14 @@ function system_modules_submit($form, &$ } // Install new modules. - foreach ($new_modules as $key => $module) { - if (!drupal_check_module($module)) { - unset($new_modules[$key]); + if (!empty($new_modules)) { + foreach ($new_modules as $key => $module) { + if (!drupal_check_module($module)) { + unset($new_modules[$key]); + } } + drupal_install_modules($new_modules); } - drupal_install_modules($new_modules); $current_module_list = module_list(TRUE, FALSE); if ($old_module_list != $current_module_list) { @@ -921,39 +911,6 @@ function system_modules_submit($form, &$ return; } - -/** - * Generate a list of dependencies for modules that are going to be switched on. - * - * @param $modules - * The list of modules to check. - * @param $form_values - * Submitted form values used to determine what modules have been enabled. - * @return - * An array of dependencies. - */ -function system_module_build_dependencies($modules, $form_values) { - static $dependencies; - - if (!isset($dependencies) && isset($form_values)) { - $dependencies = array(); - foreach ($modules as $name => $module) { - // If the module is disabled, will be switched on and it has dependencies. - if (!$module->status && $form_values['status'][$name] && isset($module->info['dependencies'])) { - foreach ($module->info['dependencies'] as $dependency) { - if (!$form_values['status'][$dependency] && isset($modules[$dependency])) { - if (!isset($dependencies[$name])) { - $dependencies[$name] = array(); - } - $dependencies[$name][] = $dependency; - } - } - } - } - } - return $dependencies; -} - /** * Uninstall functions */ @@ -2065,81 +2022,50 @@ function theme_status_report(&$requireme * An associative array containing the structure of the form. * @ingroup themeable */ -function theme_system_modules($form) { - if (isset($form['confirm'])) { - return drupal_render($form); - } - +function theme_system_modules_fieldset($form) { // Individual table headers. $header = array(); $header[] = array('data' => t('Enabled'), 'class' => 'checkbox'); $header[] = t('Name'); $header[] = t('Version'); $header[] = t('Description'); - - // Pull package information from module list and start grouping modules. - $modules = $form['validation_modules']['#value']; - foreach ($modules as $module) { - if (!isset($module->info['package']) || !$module->info['package']) { - $module->info['package'] = t('Other'); + $rows = array(); + foreach (element_children($form) as $key) { + $module = $form[$key]; + $row = array(); + unset($module['enable']['#title']); + $row[] = array('class' => 'checkbox', 'data' => drupal_render($module['enable'])); + $row[] = ''. drupal_render($module['name']) .''; + $row[] = drupal_render($module['version']); + $description = ''; + if (isset($module['help'])) { + $description = '
'. drupal_render($module['help']) .'
'; + } + $description .= drupal_render($module['description']); + if ($module['#dependencies']) { + $description .= '
' . t('Depends on: ') . implode(', ', $module['#dependencies']) . '
'; } - $packages[$module->info['package']][$module->name] = $module->info; - } - ksort($packages); - - // Display packages. - $output = ''; - foreach ($packages as $package => $modules) { - $rows = array(); - foreach ($modules as $key => $module) { - $row = array(); - $description = ''; - if (isset($form['help'][$key])) { - $description = '
'. drupal_render($form['help'][$key]) .'
'; - } - $description .= drupal_render($form['description'][$key]); - if (isset($form['status']['#incompatible_modules_core'][$key])) { - unset($form['status'][$key]); - $status = theme('image', 'misc/watchdog-error.png', t('incompatible'), t('Incompatible with this version of Drupal core')); - $description .= '
' . t('This version is incompatible with the !core_version version of Drupal core.', array('!core_version' => VERSION)) . '
'; - } - elseif (isset($form['status']['#incompatible_modules_php'][$key])) { - unset($form['status'][$key]); - $status = theme('image', 'misc/watchdog-error.png', t('incompatible'), t('Incompatible with this version of PHP')); - $php_required = $form['status']['#incompatible_modules_php'][$key]; - if (substr_count($php_required, '.') < 2) { - $php_required .= '.*'; - } - $description .= '
' . t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $php_required, '!php_version' => phpversion())) . '
'; - } - else { - $status = drupal_render($form['status'][$key]); - } - $row[] = array('data' => $status, 'class' => 'checkbox'); - - // Add labels only when there is also a checkbox. - if (isset($form['status'][$key])) { - $row[] = ''; - } - else { - $row[] = '' . drupal_render($form['name'][$key]) . ''; - } - - $row[] = array('data' => drupal_render($form['version'][$key]), 'class' => 'version'); - $row[] = array('data' => $description, 'class' => 'description'); - $rows[] = $row; + if ($module['#dependents']) { + $description .= '
' . t('Required by: ') . implode(', ', $module['#dependents']) . '
'; } - $fieldset = array( - '#title' => t($package), - '#collapsible' => TRUE, - '#collapsed' => ($package == 'Core - required'), - '#value' => theme('table', $header, $rows, array('class' => 'package')), - ); - $output .= theme('fieldset', $fieldset); + $row[] = array('data' => $description, 'class' => 'description'); + $rows[] = $row; } - $output .= drupal_render($form); - return $output; + return theme('table', $header, $rows); +} + +/** + * Themes an incompatible message. + * + * @ingroup themeable + * @param $message + * The form array representing the currently disabled modules. + * @return + * An HTML string for the message. + */ +function theme_system_modules_incompatible($message) { + return '
'. $message .'
'; } /** Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.605 diff -u -p -r1.605 system.module --- modules/system/system.module 1 Jul 2008 20:36:40 -0000 1.605 +++ modules/system/system.module 5 Jul 2008 01:58:15 -0000 @@ -115,10 +115,14 @@ function system_theme() { 'arguments' => array('form' => NULL), 'file' => 'system.admin.inc', ), - 'system_modules' => array( + 'system_modules_fieldset' => array( 'arguments' => array('form' => NULL), 'file' => 'system.admin.inc', ), + 'system_modules_incompatible' => array( + 'arguments' => array('message' => NULL), + 'file' => 'system.admin.inc', + ), 'system_modules_uninstall' => array( 'arguments' => array('form' => NULL), 'file' => 'system.admin.inc', Index: modules/system/system.test =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.test,v retrieving revision 1.8 diff -u -p -r1.8 system.test --- modules/system/system.test 29 Jun 2008 11:39:38 -0000 1.8 +++ modules/system/system.test 5 Jul 2008 01:58:15 -0000 @@ -10,7 +10,7 @@ class EnableDisableCoreTestCase extends function getInfo() { return array( 'name' => t('Module list functionality'), - 'description' => t('Enable/disable core module and confirm table creation/deletion. Enable module without dependecy enabled.'), + 'description' => t('Enable/disable core module and confirm table creation/deletion. Enable module without dependency enabled.'), 'group' => t('System') ); } @@ -35,7 +35,7 @@ class EnableDisableCoreTestCase extends $this->assertTableCount('aggregator', FALSE); $edit = array(); - $edit['status[aggregator]'] = 'aggregator'; + $edit['modules[Core - optional][aggregator][enable]'] = 'aggregator'; $this->drupalPost('admin/build/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.')); @@ -44,7 +44,7 @@ class EnableDisableCoreTestCase extends // Disable aggregator, check tables, uninstall aggregator, check tables. $edit = array(); - $edit['status[aggregator]'] = FALSE; + $edit['modules[Core - optional][aggregator][enable]'] = FALSE; $this->drupalPost('admin/build/modules', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.')); @@ -65,10 +65,10 @@ class EnableDisableCoreTestCase extends /** * Attempt to enable translation module without locale enabled. */ - function testEnableWithoutDependency () { + function testEnableWithoutDependency() { // Attempt to enable content translation without locale enabled. $edit = array(); - $edit['status[translation]'] = 'translation'; + $edit['modules[Core - optional][translation][enable]'] = 'translation'; $this->drupalPost('admin/build/modules', $edit, t('Save configuration')); $this->assertText(t('Some required modules must be enabled'), t('Dependecy required.')); @@ -114,11 +114,12 @@ class EnableDisableCoreTestCase extends module_list(TRUE, FALSE); foreach ($modules as $module) { if ($enabled) { - $this->assertTrue(module_exists($module) == $enabled, t('Module "@module" is enabled.', array('@module' => $module))); + $message = 'Module "@module" is enabled.'; } else { - $this->assertTrue(module_exists($module) == $enabled, t('Module "@module" not enabled.', array('@module' => $module))); + $message = 'Module "@module" is not enabled.'; } + $this->assertEqual(module_exists($module), $enabled, t($message, array('@module' => $module))); } } }