filename); $_coder_coders[] = $file->name; } } /** * Get all of the code review modules */ function _coder_reviews() { $reviews = array(); // get the review definitions from the include directory global $_coder_coders; if ($_coder_coders) { foreach ($_coder_coders as $coder) { $function = $coder .'_reviews'; if (function_exists($function)) { if ($review = call_user_func($function)) { $reviews = array_merge($reviews, $review); } } } } // get the contributed module review definitions if ($review = module_invoke_all('reviews')) { $reviews = array_merge($reviews, $review); } return $reviews; } /** * Implementation of hook_cron(). */ function coder_cron() { if ($use_cache = variable_get('coder_cache', 1)) { // TODO: move some of the work here... is this really worth it? } } /** * Implementation of hook_perm(). */ function coder_perm() { return array('view code review', 'view code review all'); } /** * Implementation of hook_menu(). */ function coder_menu($may_cache = TRUE) { $items = array(); if ($may_cache) { if (substr(VERSION, 0, 1) == '6') { $items['coder'] = array( 'title' => t('Code review'), 'page callback' => 'coder_page', 'access arguments' => array('view code review'), 'type' => MENU_NORMAL_ITEM, ); $items['coder/settings'] = array( 'title' => t('Selection Form'), 'page callback' => 'coder_page', 'access arguments' => array('view code review'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -2, ); $items['coder/default'] = array( 'title' => t('Default'), 'page callback' => 'coder_page', 'access arguments' => array('view code review'), 'type' => MENU_LOCAL_TASK, 'weight' => -1, ); $items['coder/core'] = array( 'title' => t('Core'), 'page callback' => 'coder_page', 'access arguments' => array('view code review'), 'type' => MENU_LOCAL_TASK, ); $items['coder/active'] = array( 'title' => t('Active'), 'page callback' => 'coder_page', 'access arguments' => array('view code review'), 'type' => MENU_LOCAL_TASK, ); $items['coder/all'] = array( 'title' => t('All'), 'page callback' => 'coder_page', 'access arguments' => array('view code review all'), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items['admin/settings/coder'] = array( 'title' => t('Code review'), 'description' => t('Select code review plugins and modules'), 'page callback' => 'drupal_get_form', 'page arguments' => array('coder_admin_settings'), 'access arguments' => array('administer site configuration'), ); } else { $items[] = array( 'path' => 'coder', 'title' => t('Code review'), 'callback' => 'coder_page', 'access' => user_access('view code review'), 'type' => MENU_NORMAL_ITEM, ); $items[] = array( 'path' => 'coder/settings', 'title' => t('Selection Form'), 'callback' => 'coder_page', 'access' => user_access('view code review'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -2, ); $items[] = array( 'path' => 'coder/default', 'title' => t('Default'), 'callback' => 'coder_page', 'access' => user_access('view code review'), 'type' => MENU_LOCAL_TASK, 'weight' => -1, ); $items[] = array( 'path' => 'coder/core', 'title' => t('Core'), 'callback' => 'coder_page', 'access' => user_access('view code review'), 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'coder/active', 'title' => t('Active'), 'callback' => 'coder_page', 'access' => user_access('view code review'), 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'coder/all', 'title' => t('All'), 'callback' => 'coder_page', 'access' => user_access('view code review all'), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items[] = array( 'path' => 'admin/settings/coder', 'title' => t('Code review'), 'description' => t('Select code review plugins and modules'), 'callback' => 'drupal_get_form', 'callback arguments' => 'coder_admin_settings', 'access' => user_access('administer site configuration'), ); } } return $items; } /** * Implementation of hook_form_alter(). */ function coder_form_alter($form_id, &$form) { if ($form_id == 'system_modules') { if (user_access('view code review')) { foreach ($form['name'] as $name => $data) { $form['name'][$name]['#value'] = l($data['#value'], "coder/$name"); } } } } /** * Helper functions for settings form */ function _coder_default_reviews() { return drupal_map_assoc(array('style', 'security')); } function _coder_settings_form($settings, &$system, &$files) { // add the javascript $path = drupal_get_path('module', 'coder'); drupal_add_js($path .'/coder.js'); // create the list of review options from the coder review plug-ins $reviews = _coder_reviews(); foreach ($reviews as $name => $review) { $review_options[$name] = l($review['#title'], $review['#link']); } // what review standards should be applied $form['coder_reviews_group'] = array( '#type' => 'fieldset', '#title' => t('Reviews'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['coder_reviews_group']['coder_reviews'] = array( '#type' => 'checkboxes', '#options' => $review_options, '#description' => t('apply the checked coding reviews'), '#default_value' => $settings['coder_reviews'], ); $form['coder_reviews_group']['coder_severity'] = array( '#type' => 'radios', '#options' => array( 1 => 'minor (most)', 5 => 'normal', 9 => 'critical (fewest)' ), '#description' => t('show warnings at or above the severity warning level'), '#default_value' => $settings['coder_severity'], ); // get the modules and theme $sql = "SELECT name, filename, type, status FROM {system} WHERE type='module' OR type='theme' ORDER BY weight ASC, filename ASC"; $result = db_query($sql); $system_modules = array(); $system_themes = array(); while ($system = db_fetch_object($result)) { $display_name = $system->name; if ($system->status) { $display_name .= t(' (active)'); $system_active[$system->name] = $system->name; } if (_coder_is_drupal_core($system)) { $display_name .= t(' (core)'); $system_core[$system->name] = $system->name; } if ($system->type == 'module') { $system_modules[$system->name] = $system->name; } else { $system_themes[$system->name] = $system->name; } $system_links[$system->name] = l($display_name, "coder/$system->name"); $files[$system->name] = $system->filename; } // display what to review options $form['coder_what'] = array( '#type' => 'fieldset', '#title' => t('What to review'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['coder_what']['coder_active_modules'] = array( // NOTE: should rename var '#type' => 'checkbox', '#default_value' => isset($settings['coder_active_modules']) ? $settings['coder_active_modules'] : 0, '#title' => t('active modules and themes'), ); $form['coder_what']['coder_core'] = array( '#type' => 'checkbox', '#default_value' => isset($settings['coder_core']) ? $settings['coder_core'] : 0, '#title' => t('core files (php, modules, and includes)'), ); $form['coder_what']['coder_includes'] = array( '#type' => 'checkbox', '#default_value' => $settings['coder_includes'], '#title' => t('include files (.inc and .php files)'), ); if (arg(0) == 'admin') { $form['coder_what']['coder_cache'] = array( '#type' => 'checkbox', '#default_value' => $settings['coder_cache'], '#title' => t('use the experimental coder cache'), ); } // display the modules in a fieldset $form['coder_what']['coder_modules'] = array( '#type' => 'fieldset', '#title' => t('Select Specific Modules'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); if (isset($settings['coder_all'])) { $modules = $system_modules; } elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) { if (isset($settings['coder_core']) && $settings['coder_core']) { $modules = array_intersect($system_active, $system_core); $modules = array_intersect($modules, $system_modules); } else { $modules = array_intersect($system_active, $system_modules); } } elseif (isset($settings['coder_core']) && $settings['coder_core']) { $modules = array_intersect($system_core, $system_modules); } elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) { $modules = array_intersect($system_active, $system_modules); } else { $modules = isset($settings['coder_modules']) && is_array($settings['coder_modules']) ? $settings['coder_modules'] : array(); } // display the themes in a fieldset $form['coder_what']['coder_themes'] = array( '#type' => 'fieldset', '#title' => t('Select Specific Themes'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); if (isset($settings['coder_all'])) { $themes = $system_themes; } elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) { if (isset($settings['coder_core']) && $settings['coder_core']) { $themes = array_intersect($system_active, $system_core); $themes = array_intersect($themes, $system_themes); } else { $themes = array_intersect($system_active, $system_themes); } } elseif (isset($settings['coder_core']) && $settings['coder_core']) { $themes = array_intersect($system_core, $system_themes); } elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) { $themes = array_intersect($system_active, $system_themes); } else { $themes = isset($settings['coder_themes']) && is_array($settings['coder_themes']) ? $settings['coder_themes'] : array(); } foreach ($system_links as $name => $link) { $classes = array(); if (in_array($name, $system_active)) { $classes[] = "coder-active"; } if (in_array($name, $system_core)) { $classes[] = "coder-core"; } if (in_array($name, $system_themes)) { $type = 'theme'; $default_value = isset($themes[$name]); } else { $type = 'module'; $default_value = isset($modules[$name]); } $form['coder_what']["coder_${type}s"]["coder_${type}s-$name"] = array( '#type' => 'checkbox', '#title' => $link, '#default_value' => $default_value, '#attributes' => array('class' => implode(' ', $classes)), ); } $system = array_merge($modules, $themes); return $form; } /** * Implementation of settings page for Drupal 5 */ function coder_admin_settings() { $settings = _coder_get_default_settings(); $form = _coder_settings_form($settings, $system, $files); $form['#submit']['coder_settings_form_submit'] = array(); $form['#submit']['system_settings_form_submit'] = array(); return system_settings_form($form); } function coder_settings_form_submit($form_id, &$form_values) { variable_set('coder_modules', _coder_settings_array($form_values, 'module')); variable_set('coder_themes', _coder_settings_array($form_values, 'theme')); } function _coder_settings_array(&$form_values, $type) { $typekey = "coder_{$type}s-"; $typelen = strlen($typekey); $systems = array(); foreach ($form_values as $key => $value) { if (substr($key, 0, $typelen) == $typekey) { if ($value == 1) { $system = substr($key, $typelen); $systems[$system] = 1; } unset($form_values[$key]); } } return $systems; } function coder_page_form_submit($form_id, $form_values) { // HELP: is there a better way to get these to coder_page_form()??? return FALSE; } /** * Implementation of code review page */ function coder_page() { return drupal_get_form('coder_page_form'); } function _coder_get_default_settings($args = 'default') { $settings['coder_reviews'] = variable_get('coder_reviews', _coder_default_reviews()); $settings['coder_severity'] = variable_get('coder_severity', 5); $settings['coder_cache'] = variable_get('coder_cache', 1); // determine any options based on the passed in URL, switch ($args) { case 'settings': $settings['coder_includes'] = 1; break; case 'active': $settings['coder_active_modules'] = 1; break; case 'core': $settings['coder_core'] = 1; $settings['coder_includes'] = 1; break; case 'all': $settings['coder_core'] = 1; $settings['coder_includes'] = 1; $settings['coder_all'] = 1; break; case 'default': $settings['coder_active_modules'] = variable_get('coder_active_modules', 1); $settings['coder_core'] = variable_get('coder_core', 0); $settings['coder_includes'] = variable_get('coder_includes', 0); $settings['coder_modules'] = variable_get('coder_modules', array()); $settings['coder_themes'] = variable_get('coder_themes', array()); break; default: $settings['coder_includes'] = 1; // TODO: does this need to go into coder_themes sometimes? $settings['coder_modules'] = array($args => $args); break; } return $settings; } function coder_page_form() { // HELP: is there a better way to get these from coder_page_form_submit()??? $form_values = $_POST; if (isset($form_values['op'])) { $settings = $form_values; $settings['coder_modules'] = _coder_settings_array($form_values, 'module'); $settings['coder_themes'] = _coder_settings_array($form_values, 'theme'); drupal_set_title(t('Code review (submitted options)')); } else { $options = arg(1); $settings = _coder_get_default_settings($options); if ($options) { drupal_set_title(t('Code review (@options)', array('@options' => isset($options) ? $options : 'default options'))); } } // get this once - list of the reviews to perform $reviews = array(); $avail_reviews = _coder_reviews(); $selected_reviews = $settings['coder_reviews']; foreach ($selected_reviews as $name => $checked) { if ($checked) { $reviews[$name] = $avail_reviews[$name]; } } if ($coder_form = _coder_settings_form($settings, $system, $files)) { // add style sheet $path = drupal_get_path('module', 'coder'); drupal_add_css($path .'/coder.css', 'module'); // code review non-module core files $module_weight = 0; if (isset($settings['coder_core']) && $settings['coder_core']) { $coder_args = array( '#reviews' => $reviews, '#severity' => $settings['coder_severity'], '#filename' => $filename, ); $form['core_php'] = array( '#type' => 'fieldset', '#title' => 'core (php)', '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => ++ $module_weight, ); $phpfiles = file_scan_directory('.', '.*\.php', array('.', '..', 'CVS'), 0, FALSE, 'name', 0); _coder_page_form_includes($form, $coder_args, 'core_php', $phpfiles, 2); $form['core_includes'] = array( '#type' => 'fieldset', '#title' => 'core (includes)', '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => ++ $module_weight, ); $includefiles = drupal_system_listing('.*\.inc$', 'includes', 'name', 0); _coder_page_form_includes($form, $coder_args, 'core_includes', $includefiles, 0); } // loop through the selected modules and themes if (isset($system)) { $dups = array(); // used to avoid duplicate includes foreach ($system as $name => $checked) { if ($checked) { // process this one file $filename = $files[$name]; if (!$filename) { drupal_set_message(t('Code Review file for %module not found', array('%module' => $name))); continue; } $coder_args = array( '#reviews' => $reviews, '#severity' => $settings['coder_severity'], '#filename' => $filename, ); $results = do_coder_reviews($coder_args); // output the results in a collapsible fieldset $form[$name] = array( '#type' => 'fieldset', '#title' => $filename, '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => ++ $module_weight, ); if (count($results) == 0) { $results[] = t('No Problems Found'); } else { $form[$name]['#collapsed'] = FALSE; } $form[$name]['output'] = array( '#value' => theme('coder', $name, $filename, $results), '#weight' => -1, ); // process the same directory include files if ($settings['coder_includes']) { // NOTE: convert to the realpath here so drupal_system_listing // doesn't return additional paths (i.e., try "module"). $path = str_replace('\\', '/', dirname(realpath($filename))); $offset = strpos($path, dirname($filename)); if (!isset($dups[$path])) { if (substr($filename, -7) == '.module') { $coder_args['#php_minor'] = 1; } $dups[$path] = 1; $includefiles = drupal_system_listing('.*\.(inc|php)$', $path, 'name', 0); _coder_page_form_includes($form, $coder_args, $name, $includefiles, $offset); } } } } } // prepend the settings form $form['settings'] = array( '#type' => 'fieldset', '#title' => t('Selection Form'), '#collapsible' => TRUE, '#collapsed' => isset($form), '#weight' => -1, ); if ($form['settings']['#collapsed']) { $form['settings']['#prefix'] = t('
'. check_plain($line) .''; } } $class = "coder-warning"; if ($severity_name) { $class .= " coder-$severity_name"; } $path = drupal_get_path('module', 'coder'); $img = theme('image', $path ."/images/$severity_name.png", t('severity: @severity', array('@severity' => $severity_name)), '', array('align' => 'right', 'class' => 'coder'), FALSE); return '