Newer
Older
Gábor Hojtsy
committed
// $Id$
// This module holds functions useful for Drupal development.
// Please contribute!
Moshe Weitzman
committed
// suggested profiling and stacktrace library from http://www.xdebug.org/index.php
// if you activate this extension, this module will use it.
// you probably want these php.ini or .htaccess directives:
// xdebug.auto_profile=1
// xdebug.auto_profile_mode=3
Moshe Weitzman
committed
// xdebug.default_enable
Moshe Weitzman
committed
define('DEVEL_QUERY_SORT_BY_SOURCE', 0);
define('DEVEL_QUERY_SORT_BY_DURATION', 1);
Moshe Weitzman
committed
define('DEVEL_ERROR_HANDLER_NONE', 0);
define('DEVEL_ERROR_HANDLER_STANDARD', 1);
define('DEVEL_ERROR_HANDLER_BACKTRACE', 2);
Moshe Weitzman
committed
define('DEVEL_MIN_TEXTAREA', 50);
function devel_help($section) {
switch ($section) {
case 'admin/settings/devel':
return '<p>'. t('Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the !block page.', array('!block' => l(t('block administration'), 'admin/build/block'))). '</p>';
case 'devel/reference':
return '<p>'. t('This is a list of defined user functions that generated this current request lifecycle. Click on a function name to view its documention.'). '</p>';
Moshe Weitzman
committed
return '<p>'. t('Clicking a module\'s reinstall button will simulate uninstalling/installing a module. <code>hook_uninstall()</code> and <code>hook_install()</code> will be executed and the schema version number will be set to the most recent update number. You may have to manually clear out any existing tables first if the module doesn\'t implement <code>hook_uninstall()</code>.'). '</p>';
case 'devel/session':
return '<p>'. t('Here are the contents of your <code>$_SESSION</code> variable.'). '</p>';
case 'devel/variable':
return '<p>'. t('This is a list of the variables and their values currently stored in variables table and the <code>$conf</code> array of your settings.php file. These variables are usually accessed with <a href="@variable-get-doc">variable_get()</a> and <a href="@variable-set-doc">variable_set()</a>. Variables that are too long can slow down your pages.', array('@variable-get-doc' => 'http://api.drupal.org/api/HEAD/function/variable_get', '@variable-set-doc' => 'http://api.drupal.org/api/HEAD/function/variable_set')).'</p>';
Moshe Weitzman
committed
}
/**
* Implementation of hook_menu().
*/
function devel_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array('path' => 'devel/cache/clear',
'callback' => 'devel_cache_clear',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
Moshe Weitzman
committed
$items[] = array('path' => 'devel/rebuild_node_comment_statistics',
'title' => t('Rebuild node_comment_statistics table'),
'callback' => 'devel_rebuild_node_comment_statistics_page',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
$items[] = array('path' => 'devel/queries',
'title' => t('Database queries'),
'callback' => 'devel_queries',
'access' => user_access('access devel information'));
$items[] = array('path' => 'devel/queries/empty',
'title' => t('Empty database queries'),
'callback' => 'devel_queries_empty',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'devel/reference',
'title' => t('function reference'),
'callback' => 'devel_function_reference',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
$items[] = array('path' => 'devel/reinstall',
'title' => t('Reinstall modules'),
Neil Drumm
committed
'callback' => 'devel_reinstall',
'access' => user_access('access devel information'),
Neil Drumm
committed
);
if (module_exists('menu')) {
$items[] = array('path' => 'devel/menu/reset',
'callback' => 'drupal_get_form',
'callback arguments' => 'devel_menu_reset_form',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
}
$items[] = array('path' => 'devel/variable',
Moshe Weitzman
committed
'title' => t('Variable editor'),
'callback' => 'devel_variable_page',
Moshe Weitzman
committed
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
$items[] = array('path' => 'devel/variable/edit',
'title' => t('Variable editor'),
'callback' => 'drupal_get_form',
'callback arguments' => array('devel_variable_edit'),
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
$items[] = array('path' => 'devel/variable/delete',
'title' => t('Variable editor'),
'callback' => 'drupal_get_form',
'callback arguments' => array('devel_variable_delete'),
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
'title' => t('Session viewer'),
'callback' => 'devel_session',
'access' => user_access('access devel information'),
'type' => MENU_CALLBACK,
);
$items[] = array('path' => 'devel/switch',
'title' => t('Switch user'),
'callback' => 'devel_switch_user',
'access' => user_access('switch users'),
'type' => MENU_CALLBACK,
);
Moshe Weitzman
committed
$items[] = array(
'path' => 'admin/settings/devel',
'callback' => 'drupal_get_form',
'callback arguments' => array('devel_admin_settings'),
Moshe Weitzman
committed
'access' => user_access('administer site configuration'),
'type' => MENU_NORMAL_ITEM
);
if (is_numeric(arg(1))) {
if (arg(0) == 'node') {
Moshe Weitzman
committed
$items[] = array('path' => 'node/'. arg(1) .'/load',
Moshe Weitzman
committed
'callback' => 'devel_load_object',
'callback arguments' => array('node', arg(1)),
'access' => user_access('access devel information'),
'type' => MENU_LOCAL_TASK,
);
$items[] = array('path' => 'node/'. arg(1) .'/render',
Moshe Weitzman
committed
'callback' => 'devel_render_object',
'callback arguments' => array('node', arg(1)),
'access' => user_access('access devel information'),
'type' => MENU_LOCAL_TASK,
);
}
elseif (arg(0) == 'user') {
Moshe Weitzman
committed
$items[] = array('path' => 'user/'. arg(1) .'/load',
Moshe Weitzman
committed
'callback' => 'devel_load_object',
'callback arguments' => array('user', arg(1)),
'access' => user_access('access devel information'),
'type' => MENU_LOCAL_TASK,
);
}
Moshe Weitzman
committed
/*
* TODO: this is very naive. We don't preserve views arguments like other tabs.
Moshe Weitzman
committed
* I tried, but it I started borrowing too much Views menu code. I think
* we need some refactoring in Views!
* I concluded that the result and 'render' operations yield no useful info
* so no tabs exist for those.
*/
if (module_exists('views_ui')) {
$urls = views_get_all_urls();
foreach ($urls as $view_name => $url) {
Moshe Weitzman
committed
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
$items[] = array('path' => "$url/load",
'title' => t('Dev load'),
'callback' => 'devel_load_object',
'callback arguments' => array('view', $view_name),
'access' => user_access('administer views'),
'type' => MENU_LOCAL_TASK,
'weight' => 8,
);
$items[] = array('path' => "$url/queries",
'title' => t('Dev queries'),
'callback' => 'devel_views_object',
'callback arguments' => array('queries', $view_name),
'access' => user_access('administer views'),
'type' => MENU_LOCAL_TASK,
'weight' => 9,
);
$items[] = array('path' => "$url/items",
'title' => t('Dev items'),
'callback' => 'devel_views_object',
'callback arguments' => array('items', $view_name),
'access' => user_access('administer views'),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
}
}
drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css');
drupal_add_js(drupal_get_path('module', 'devel') .'/devel.js');
return $items;
}
Moshe Weitzman
committed
function devel_views_object($type, $view_name) {
$view = views_get_view($view_name);
$return = views_build_view($type, $view);
// dvr($return);
return devel_print_object($return);
}
/**
* Implementation of hook_init(). Avoids custom error handling for better
* behavior when stepping though in a debugger.
*/
function devel_init() {
if (strstr($_SERVER['PHP_SELF'], 'update.php') || strstr($_GET['q'], 'autocomplete') || $_GET['q'] == 'upload/js' || substr($_GET['q'], 0, strlen('system/files')) == 'system/files') {
// update.php relies on standard error handler. avoid breaking a few other pages.
Moshe Weitzman
committed
}
Moshe Weitzman
committed
// no css or handler if we are serving a cached page
if (function_exists('drupal_set_content')) {
Moshe Weitzman
committed
if (user_access('access devel information')) {
drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css');
$handler = variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD);
switch ($handler) {
case DEVEL_ERROR_HANDLER_STANDARD:
// do nothing
break;
case DEVEL_ERROR_HANDLER_BACKTRACE:
set_error_handler('backtrace_error_handler');
break;
case DEVEL_ERROR_HANDLER_NONE:
restore_error_handler();
break;
}
Moshe Weitzman
committed
}
}
else {
// we need user_access() in the shutdown function
drupal_load('module', 'user');
}
register_shutdown_function('devel_shutdown');
if (variable_get('dev_mem', 0) && function_exists('memory_get_usage')) {
global $memory_init;
$memory_init = memory_get_usage();
}
Moshe Weitzman
committed
}
}
function backtrace_error_handler($errno, $message, $filename, $line) {
if ($errno & (E_ALL ^ E_NOTICE)) {
$types = array(1 => 'error', 2 => 'warning', 4 => 'parse error', 8 => 'notice', 16 => 'core error', 32 => 'core warning', 64 => 'compile error', 128 => 'compile warning', 256 => 'user error', 512 => 'user warning', 1024 => 'user notice', 2048 => 'strict warning');
$entry = $types[$errno] .': '. $message .' in '. $filename .' on line '. $line .'.';
if (variable_get('error_level', 1) == 1) {
$backtrace = debug_backtrace();
array_shift($backtrace);
$rows[0][] = array('data' => '<strong>'. $entry. '</strong>', 'colspan' => 3);
$i=1;
foreach ($backtrace as $trace) {
$rows[$i][] = $trace['class']. $trace['type']. l($trace['function'], "http://api.drupal.org/api/HEAD/function/". $trace['function']);
$rows[$i][] = $trace['file'] ? $trace['file']. ': '. $trace['line'] : '';
if (!empty($trace['args'])) {
foreach ($trace['args'] as $arg) {
if (is_array($arg) || is_object($arg)) {
$args[] = dpr($arg, TRUE);
}
else {
$args[] = check_plain($arg);
}
}
$rows[$i][] = implode(', ', $args);
$i++;
unset($args);
Moshe Weitzman
committed
}
}
if (function_exists('theme_table')) {
$header = array('function', 'file: line', 'arguments');
print theme('table', $header, $rows);
}
else {
print_r($rows);
}
}
watchdog('php', t('%message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line)), WATCHDOG_ERROR);
/**
* Implementation of hook_perm().
*/
function devel_perm() {
return array('access devel information', 'execute php code', 'switch users');
}
/**
* Implementation of hook_block().
*/
The Great Git Migration
committed
function devel_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$blocks[0]['info'] = t('Switch user');
$blocks[1]['info'] = t('Devel');
$blocks[2]['info'] = t('Execute PHP');
The Great Git Migration
committed
else if ($op == 'configure' && $delta == 0) {
$form['devel_switch_user_list_size'] = array(
'#type' => 'textfield',
'#title' => t('Number of users to display in the list'),
'#default_value' => variable_get('devel_switch_user_list_size', 10),
'#size' => '3',
'#maxlength' => '4',
);
return $form;
}
else if ($op == 'save' && $delta == 0) {
variable_set('devel_switch_user_list_size', $edit['devel_switch_user_list_size']);
}
else if ($op == 'view') {
switch ($delta) {
case 0:
$block['subject'] = t('Switch user');
$links = devel_switch_user_list();
if (!empty($links)) {
$block['content'] = theme('item_list', $links);
$block['content'] .= drupal_get_form('devel_switch_user_form');
$links = array();
$block['subject'] = t('devel');
if (user_access('access devel information')) {
$links[] = l('Devel settings', 'admin/settings/devel', array('title' => t('Adjust module settings for devel module')));
$links[] = l('Empty cache', 'devel/cache/clear', array('title' => t('Clear the database cache tables which store page, menu, node, and variable caches.')), drupal_get_destination());
$links[] = l('Run cron', 'admin/logs/status/run-cron', array('title' => t('Execute functions scheduled for cron runs.')), drupal_get_destination());
$links[] = l('Phpinfo()', 'admin/logs/status/php');
$links[] = l('Function reference', 'devel/reference', array('title' => t('View a list of currently defined user functions with documentation links')));
$links[] = l('Reinstall modules', 'devel/reinstall', array('title' => t('Re-run hook_install() for a given module')));
$links[] = l('Reset menus', 'devel/menu/reset', array('title' => t('Resets all menu items to their default settings')));
Moshe Weitzman
committed
$links[] = l('Variable editor', 'devel/variable', array('title' => t('Edit and delete site variables')));
$links[] = l('Session viewer', 'devel/session', array('title' => t('List the contents of $_SESSION')));
if (function_exists('devel_node_access_perm') && user_access(DNA_ACCESS_VIEW)) {
// True only if devel_node_access enabled.
$links[] = l('Node access summary', 'devel/node_access/summary');
if ($links) {
$block['content'] = theme('item_list', $links);
}
break;
case 2:
if (user_access('execute php code')) {
$block['content'] = drupal_get_form('devel_execute_form');
}
return $block;
}
}
function devel_switch_user_list() {
$links = array();
if (user_access('switch users')) {
The Great Git Migration
committed
$list_size = variable_get('devel_switch_user_list_size', 10);
$dest = drupal_get_destination();
The Great Git Migration
committed
// Try to find at least $list_size users that can switch.
$roles = user_roles(1, 'switch users');
if (isset($roles[2])) {
// If authenticated users have this permission, just grab
The Great Git Migration
committed
// the last $list_size users, since there won't be records in
// {user_roles} and every user on the system can switch.
The Great Git Migration
committed
$users = db_query_range("SELECT DISTINCT u.uid, u.name, u.access FROM {users} u WHERE u.uid > 0 ORDER BY u.access DESC", 0, $list_size);
}
else {
$where = array('u.uid = 1');
if (count($roles)) {
$where[] = 'r.rid IN ('. implode(',', array_keys($roles)) .')';
}
$where_sql = implode(' OR ', $where);
The Great Git Migration
committed
$users = db_query_range("SELECT DISTINCT u.uid, u.name, u.access FROM {users} u LEFT JOIN {users_roles} r ON u.uid = r.uid WHERE $where_sql ORDER BY u.access DESC", 0, $list_size);
}
while ($user = db_fetch_object($users)) {
$links[$user->uid] = l(theme('placeholder', $user->name), 'devel/switch/'. $user->name, array('title' => t('This user can switch back.')), $dest, NULL, FALSE, TRUE);
}
$num_links = count($links);
The Great Git Migration
committed
if ($num_links < $list_size) {
// If we don't have enough, add distinct uids until we hit $list_size.
$users = db_query_range('SELECT uid, name, access FROM {users} WHERE uid > 0 AND uid NOT IN ('. implode(',', array_keys($links)) .') ORDER BY access DESC', 0, $list_size - $num_links);
while (($user = db_fetch_object($users)) && count($links) < $list_size) {
$links[$user->uid] = l($user->name, 'devel/switch/'. $user->name, array('title' => t('Caution: this user will be unable to switch back.')), $dest);
}
}
}
return $links;
}
function devel_switch_user_form() {
$form['username'] = array(
'#type' => 'textfield',
'#description' => t('Enter username'),
The Great Git Migration
committed
'#autocomplete_path' => 'user/autocomplete',
'#maxlength' => USERNAME_MAX_LENGTH,
'#size' => 16,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Switch'),
);
return $form;
}
function devel_switch_user_form_validate($form_id, $form_values) {
if (!$account = user_load(array('name' => $form_values['username']))) {
form_set_error('username', t('Username not found'));
}
}
function devel_switch_user_form_submit($form_id, $form_values) {
return 'devel/switch/'. $form_values['username'];
}
/**
* Implementation of hook_form_alter().
*/
function devel_form_alter($form_id, &$form, $key_in = NULL) {
if (user_access('access devel information') && variable_get('devel_form_weights', 0)) {
$children = element_children($form);
if (empty($children)) {
if (isset($form['#type']) && !in_array($form['#type'], array('value', 'hidden'))) {
if (!isset($form['#title'])) {
$form['#title'] = '';
}
$form['#title'] .= " (key=$key_in, weight=". (isset($form['#weight']) ? $form['#weight'] : 0) .')';
}
}
else {
foreach (element_children($form) as $key) {
// We need to add the weight to fieldsets.
if (element_children($form[$key])) { // Which are a container of others.
if (!isset($form[$key]['#title'])) {
$form[$key]['#title'] = '';
}
$form[$key]['#title'] .= " (key=$key, weight=". (isset($form[$key]['#weight']) ? $form[$key]['#weight'] : 0) .')';
devel_form_alter($form_id, $form[$key], $key);
Moshe Weitzman
committed
}
Jonathan Chaffer
committed
function devel_exit($destination = NULL) {
Moshe Weitzman
committed
global $user;
Jonathan Chaffer
committed
if (isset($destination)) {
// The page we are leaving is a drupal_goto(). Present a redirection page
// so that the developer can see the intermediate query log.
The Great Git Migration
committed
if (isset($user) && function_exists('user_access') && user_access('access devel information') && variable_get('devel_redirect_page', 0)) {
$output = t('<p>The user is being redirected to <a href="@destination">@destination</a>.</p>', array('@destination' => $destination));
Gerhard Killesreiter
committed
print theme('page', $output);
Jonathan Chaffer
committed
// Don't allow the automatic redirect to happen.
drupal_page_footer();
exit();
}
else {
// Make sure not to print anything before the automatic redirect.
return;
}
Jonathan Chaffer
committed
}
Moshe Weitzman
committed
}
Moshe Weitzman
committed
/**
* See devel_init() which registers this function as a shutdown function. Displays developer information in the footer.
*/
function devel_shutdown() {
Moshe Weitzman
committed
global $queries, $memory_init, $user;
Moshe Weitzman
committed
$output = '';
Moshe Weitzman
committed
// use $GLOBALS['devel_shutdown'] = FALSE in order to supress devel footer for a page. not necessary if your page
// outputs a text/javascript or text/xml Content-type http header. Thats advised where applicable.
if ($GLOBALS['devel_shutdown'] !== FALSE) {
// Try not to break non html pages.
if (function_exists('drupal_get_headers')) {
$headers = drupal_get_headers();
Moshe Weitzman
committed
if(strstr($headers, 'xml') || strstr($headers, 'javascript') || strstr($headers, 'plain')|| strstr($headers, 'image')) {
Moshe Weitzman
committed
return;
}
Moshe Weitzman
committed
// don't append to CLI scripts
if (empty($_SERVER['REQUEST_METHOD'])) {
return;
}
Moshe Weitzman
committed
if (isset($user) && user_access('access devel information')) {
list($counts, $query_summary) = devel_query_summary();
// Query log off, timer on.
if (!variable_get('devel_query_display', 0) && variable_get('dev_timer', 0)) {
$output = '<div class="dev-timer">'. devel_timer() .' '. $query_summary. '</div>';
}
// Query log on.
$sum = 0;
if (variable_get('devel_query_display', FALSE)) {
$output .= '<div class="dev-query">';
$output .= $query_summary;
if (function_exists('theme_table')) {
$txt .= t(' Queries taking longer than %threshold ms and queries executed more than once, are <span class="marker">highlighted</span>.', array('%threshold' => variable_get('devel_execution', 5)));
if (variable_get('dev_timer', 0)) {
$txt .= devel_timer();
}
$output .= $txt. devel_query_table($queries, $counts);
else {
$output .= $txt;
ob_start();
dprint_r($queries);
$output .= ob_get_clean();
}
$output .= '</div>';
if (variable_get('dev_mem', FALSE) && function_exists('memory_get_usage')) {
$memory_shutdown = memory_get_usage();
$list = array();
foreach (array('devel_init()' => $memory_init, 'devel_shutdown()' => $memory_shutdown) as $type => $value) {
$list[] = t('Memory used at %type: %value MB', array('%type' => $type, '%value' => round($value / 1024 / 1024, 2)));
}
$output .= '<div class="dev-memory-usage"><h3>'. 'Memory usage:' .'</h3>'. theme('item_list', $list) .'</div>';
// TODO: gzip this text if we are sending a gzip page. see drupal_page_header().
if ($output) {
print $output;
}
}
Moshe Weitzman
committed
devel_store_queries();
}
function devel_store_queries() {
if (variable_get('devel_store_queries', 0) && rand(1, variable_get('devel_store_random', 1)) == 1) {
Moshe Weitzman
committed
global $active_db, $queries;
$qids = array();
$values = array();
$fields = array();
// We need this for the devel_queries insert below.
setlocale(LC_NUMERIC, 'C');
foreach ($queries as $value) {
list($function, $query) = explode("\n", $value[0]);
$query = preg_replace(array("/'.*'/s", "/\d.*\.\d.*/", "/\d.*/"), array("S", "F", "D"), $query);
$hash = md5($function . $query);
if (!isset($qids[$hash])) {
$qids[$hash] = db_result(devel_db_query("SELECT qid FROM {devel_queries} WHERE hash = '%s'", $hash));
if (!$qids[$hash]) {
devel_db_query("INSERT INTO {devel_queries} (query, function, hash) VALUES ('%s', '%s', '%s')", $query, $function, $hash);
$qids[$hash] = mysql_insert_id();
}
}
$fields[] = "(%d, '%f')";
$values[] = $qids[$hash];
$values[] = $value[1];
}
if (count($fields)) {
devel_db_query('INSERT INTO {devel_times} (qid, time) VALUES '. implode(',', $fields), $values);
}
}
}
Moshe Weitzman
committed
function devel_query_summary() {
if (variable_get('dev_query', FALSE)) {
global $queries;
foreach ($queries as $query) {
$text[] = $query[0];
$sum += $query[1];
}
$counts = array_count_values($text);
Moshe Weitzman
committed
return array($counts, t_safe('Executed %queries queries in %time milliseconds.', array('%queries' => count($queries), '%time' => round($sum * 1000, 2))));
Moshe Weitzman
committed
}
}
Moshe Weitzman
committed
function t_safe($string) {
$args = func_get_args();
return function_exists('t') ? call_user_func_array('t', $args) : call_user_func_array('strtr', $args);
}
* Returns a list of all currently defined user functions in the current
* request lifecycle, with links their documentation.
*/
$functions = get_defined_functions();
$ufunctions = $functions['user'];
sort($ufunctions);
foreach($ufunctions as $function) {
$links[] = l($function, "http://api.drupal.org/api/HEAD/function/$function");
}
return theme('item_list', $links);
function devel_db_query($query) {
global $active_db;
$args = func_get_args();
array_shift($args);
$query = db_prefix_tables($query);
if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
$args = $args[0];
}
_db_query_callback($args, TRUE);
$query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
return mysql_query($query, $active_db);
Moshe Weitzman
committed
function devel_admin_settings() {
Moshe Weitzman
committed
$form['queries'] = array('#type' => 'fieldset', '#title' => t('Query log'));
The Great Git Migration
committed
$description = t("Collect query info. If disabled, no query log functionality will work.");
if (extension_loaded('Zend Optimizer')) {
$description = t('You must disable the php Zend Optimizer extension in order to enable this feature. Zend Optimizer is <a href="!url">horribly buggy and segfaults your Apache</a> ... ', array('!url' => url('http://drupal.org/node/126098'))). $description;
}
Moshe Weitzman
committed
$form['queries']['dev_query'] = array('#type' => 'checkbox',
'#title' => t('Collect query info'),
'#default_value' => variable_get('dev_query', 0),
The Great Git Migration
committed
'#description' =>$description,
'#disabled' => extension_loaded('Zend Optimizer') ? TRUE : FALSE,
);
Moshe Weitzman
committed
$form['queries']['devel_query_display'] = array('#type' => 'checkbox',
'#title' => t('Display query log'),
'#default_value' => variable_get('devel_query_display', 0),
Moshe Weitzman
committed
'#description' => t('Display a log of the database queries needed to generate the current page, and the execution time for each. Also, queries which are repeated during a single page view are summed in the # column, and printed in red since they are candidates for caching.'));
$form['queries']['devel_query_sort'] = array('#type' => 'radios',
'#title' => t('Sort query log'),
'#default_value' => variable_get('devel_query_sort', DEVEL_QUERY_SORT_BY_SOURCE),
'#options' => array(t('by source'), t('by duration')),
'#description' => t('The query table can be sorted in the order that the queries were executed or by descending duration.'),
);
Moshe Weitzman
committed
$form['queries']['devel_execution'] = array('#type' => 'textfield',
'#title' => t('Slow query highlighting'),
'#default_value' => variable_get('devel_execution', 5),
'#size' => 4,
'#maxlength' => 4,
Moshe Weitzman
committed
'#description' => t('Enter an integer in milliseconds. Any query which takes longer than this many milliseconds will be highlighted in the query log. This indicates a possibly inefficient query, or a candidate for caching.'),
);
$form['queries']['devel_store_queries'] = array('#type' => 'checkbox',
'#title' => t('Store executed queries'),
'#default_value' => variable_get('devel_store_queries', 0),
Moshe Weitzman
committed
'#description' => t('Store statistics about executed queries. See the devel_x tables. This feature is currently only available for the MySQL database backend.'));
$form['queries']['devel_store_random'] = array('#type' => 'textfield',
'#title' => t('Sampling interval'),
'#default_value' => variable_get('devel_store_random', 1),
'#size' => 4,
Moshe Weitzman
committed
'#description' => t('If storing query statistics, only store every nth page view. 1 means every page view, 2 every second, and so on.'));
Moshe Weitzman
committed
$form['dev_timer'] = array('#type' => 'checkbox',
'#title' => t('Display page timer'),
'#default_value' => variable_get('dev_timer', 0),
'#description' => t('Display page execution time in the query log box.'),
);
Moshe Weitzman
committed
$form['dev_mem'] = array('#type' => 'checkbox',
'#title' => t('Display memory usage'),
'#default_value' => variable_get('dev_mem', 0),
'#description' => t('Display how much memory is used to generate the current page. This will show memory usage when devel_init() is called and when devel_exit() is called. PHP must have been compiled with the <em>--enable-memory-limit</em> configuration option for this feature to work.'),
Moshe Weitzman
committed
$form['devel_redirect_page'] = array('#type' => 'checkbox',
'#title' => t('Display redirection page'),
'#default_value' => variable_get('devel_redirect_page', 0),
'#description' => t('When a module executes drupal_goto(), the query log and other developer information is lost. Enabling this setting presents an intermediate page to developers so that the log can be examined before continuing to the destination page.'),
);
Moshe Weitzman
committed
$form['devel_form_weights'] = array('#type' => 'checkbox',
'#title' => t('Display form element keys and weights'),
'#default_value' => variable_get('devel_form_weights', 0),
'#description' => t('Form element names are needed for performing themeing or altering a form. Their weights determine the position of the element. Enabling this setting will show these keys and weights beside each form item.'),
Moshe Weitzman
committed
$form['devel_error_handler'] = array('#type' => 'radios',
'#title' => t('Error handler'),
'#default_value' => variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD),
'#options' => array(DEVEL_ERROR_HANDLER_NONE => t('None'), DEVEL_ERROR_HANDLER_STANDARD => t('Standard drupal'), DEVEL_ERROR_HANDLER_BACKTRACE => t('Backtrace')),
'#description' => t('Choose an error handler for your site. <em>Backtrace</em> prints nice debug information when an error is noticed, and you !choose. <em>None</em> is a good option when stepping through the site in your debugger.', array('!choose' => l(t('to show errors on screen'), 'admin/settings/error-reporting'))),
);
// Save any old SMTP library
if (variable_get('smtp_library', '') != '' && variable_get('smtp_library', '') != drupal_get_filename('module', 'devel')) {
variable_set('devel_old_smtp_library', variable_get('smtp_library', ''));
}
$smtp_options = array(
'' => t('Default'),
drupal_get_filename('module', 'devel') => t('Log only'),
);
if (variable_get('devel_old_smtp_library', '') != '') {
$smtp_options[variable_get('devel_old_smtp_library', '')] = t('Other (!library)', array('!library' => variable_get('devel_old_smtp_library', '')));
}
$form['smtp_library'] = array(
'#type' => 'radios',
'#title' => t('SMTP library'),
'#options' => $smtp_options,
'#default_value' => variable_get('smtp_library', ''),
);
return system_settings_form($form);
/**
* Menu callback; clears all caches, then redirects to the previous page.
*/
function devel_cache_clear() {
// clear preprocessor cache
drupal_clear_css_cache();
// clear core tables
$core = array('cache', 'cache_filter', 'cache_menu', 'cache_page');
$alltables = array_merge($core, module_invoke_all('devel_caches'));
foreach ($alltables as $table) {
}
/**
* Generates the execute block form.
function devel_execute_form() {
$form['code'] = array(
'#type' => 'textarea',
'#title' => t('PHP code to execute'),
'#description' => t('Enter some code. Do not use <code><?php ?></code> tags.')
);
$form['op'] = array('#type' => 'submit', '#value' => t('Execute'));
$form['#redirect'] = FALSE;
$form['#skip_duplicate_check'] = TRUE;
return $form;
Moshe Weitzman
committed
}
* Process PHP execute form submissions.
function devel_execute_form_submit($form_id, $form) {
ob_start();
print eval($form['code']);
dsm(ob_get_clean());
* Menu callback; clear the database, resetting the menu to factory defaults.
function devel_menu_reset_form() {
return confirm_form(array(),
t('Are you sure you want to reset all menu items to their default settings?'),
'admin/build/menu',
t('Any custom additions or changes to the menu will be lost.'),
t('Reset all'),
t('Cancel')
);
Gerhard Killesreiter
committed
/**
* Process menu reset form submission.
Gerhard Killesreiter
committed
*/
function devel_menu_reset_form_submit() {
db_query('DELETE FROM {menu}');
$mid = module_invoke('menu', 'edit_item_save', array('title' => t('Primary links'), 'pid' => 0, 'type' => MENU_CUSTOM_MENU));
variable_set('menu_primary_menu', $mid);
variable_set('menu_secondary_menu', $mid);
drupal_set_message(t('The menu items have been reset to their default settings.'));
return 'admin/build/menu';
Neil Drumm
committed
}
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
/**
* Implementation of hook_forms().
*/
function devel_forms() {
$forms = array();
if (user_access('access devel information')) {
// registers each devel_reinstall_$module form_id
$modules = module_list();
foreach ($modules as $module) {
$forms['devel_reinstall_'. $module]['callback'] = 'devel_reinstall_form';
}
}
return $forms;
}
function devel_reinstall_form($module) {
$form = array(
'#base' => 'devel_reinstall',
'submit' => array(
'#type' => 'submit',
'#value' => t('Reinstall @name module', array('@name' => $module))
),
);
return $form;
}
/**
* Menu callback; Display a list of installed modules with the option to reinstall them via hook_install.
*/
Neil Drumm
committed
function devel_reinstall() {
$output = '';
$modules = module_list();
sort($modules);
foreach ($modules as $module) {
$output .= drupal_get_form('devel_reinstall_'. $module, $module);
Neil Drumm
committed
}
Moshe Weitzman
committed
drupal_set_message(t('Warning - will delete your module tables and variables.'), 'error');
Neil Drumm
committed
return $output;
}
/**
* Process reinstall menu form submissions.
*/
Neil Drumm
committed
function devel_reinstall_submit($form_id, $form_values) {
include_once './includes/install.inc';
$module = str_replace('devel_reinstall_', '', $form_id);
Moshe Weitzman
committed
module_load_install($module);
Neil Drumm
committed
$versions = drupal_get_schema_versions($module);
drupal_set_installed_schema_version($module, $versions ? max($versions) : SCHEMA_INSTALLED);
Moshe Weitzman
committed
module_invoke($module, 'uninstall');
Neil Drumm
committed
module_invoke($module, 'install');
drupal_set_message(t('Reinstalled the %name module.', array('%name' => $module)));
}
Gerhard Killesreiter
committed
/**
* Menu callback; display all variables.
Gerhard Killesreiter
committed
*/
function devel_variable_page() {
// we print our own page so as to avoid blocks
$output = drupal_get_form('devel_variable');
print theme('page', $output, FALSE);
}
Moshe Weitzman
committed
$header = array(
array(''),
array('data' => t('Name'), 'field' => 'name', 'sort' => 'asc'),
array('data' => t('Value'), 'field' => 'value'),
array('data' => t('Length'), 'field' => 'length'),
array('data' => t('Operations')),
);
// TODO: we could get variables out of $conf but that would include hard coded ones too. ideally i would highlight overrridden/hard coded variables
switch ($GLOBALS['db_type']) {
case 'mssql':
$sql = "SELECT *, COL_LENGTH('{variable}', 'value') AS length FROM {variable}";
break;
default:
$sql = "SELECT *, LENGTH(value) AS length FROM {variable}";
break;
}
Moshe Weitzman
committed
$result = db_query($sql. tablesort_sql($header));
while ($row = db_fetch_object($result)) {
$variables[$row->name] = '';
$form['name'][$row->name] = array('#value' => check_plain($row->name));
if (drupal_strlen($row->value) > 70) {
$value = drupal_substr($row->value, 0, 65) .'...';
Moshe Weitzman
committed
}
else {
$value = $row->value;
}
$form[$row->name]['value'] = array('#value' => check_plain($value));
Moshe Weitzman
committed
$form[$row->name]['length'] = array('#value' => $row->length);
$form[$row->name]['edit'] = array('#value' => l(t('edit'), "devel/variable/edit/$row->name"));
}
$form['variables'] = array('#type' => 'checkboxes', '#options' => $variables);
$form['submit'] = array(
'#type' => 'submit',
Moshe Weitzman
committed
'#value' => t('Delete'),
);
return $form;
}
function theme_devel_variable($form) {
$children = element_children($form['name']);
foreach ($children as $key) {
Moshe Weitzman
committed
$rows[] = array(
drupal_render($form['variables'][$key]),
drupal_render($form['name'][$key]),
drupal_render($form[$key]['value']),
drupal_render($form[$key]['length']),
drupal_render($form[$key]['edit']),
);
}
$header = array(
Moshe Weitzman
committed
theme('table_select_header_cell'),
Moshe Weitzman
committed
array('data' => t('Name'), 'field' => 'name', 'sort' => 'asc'),
array('data' => t('Value'), 'field' => 'value'),
array('data' => t('Length'), 'field' => 'length'),
array('data' => t('Operations'), 'colspan' => 2),
);
$output = theme('table', $header, $rows);
$output .= drupal_render($form);
return $output;
}
function devel_variable_submit($form_id, $form_values) {
$deletes = array_filter($form_values['variables']);
array_walk($deletes, 'variable_del');
drupal_set_message(format_plural(count($deletes), 'one variable deleted', '@count variables deleted'));
Moshe Weitzman
committed
}
function devel_variable_edit($name) {
$value = variable_get($name, 'not found');
$form['name'] = array(
'#type' => 'value',
Moshe Weitzman
committed
'#value' => $name
);
$form['value'] = array(
'#type' => 'item',
'#title' => t('Old value'), // maybe check_plain() done by fapi
Moshe Weitzman
committed
);
if (is_string($value) || is_numeric($value)) {
'#type' => 'textarea',
'#title' => t('New value'),
'#default_value' => $value
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
}
else {
$form['new'] = array(
'#type' => 'item',
'#title' => t('New value'),
'#value' => t('Sorry, complex variable types may not be edited yet. Use the <em>Execute PHP</em> block and the <a href="@variable-set-doc">variable_set()</a> function.', array('@variable-set-doc' => 'http://api.drupal.org/api/HEAD/function/variable_set'))
);
}
Moshe Weitzman
committed
drupal_set_title($name);
return $form;
}
function devel_variable_edit_submit($form_id, $form_values) {
variable_set($form_values['name'], $form_values['new']);
drupal_set_message(t('Saved new value for %name', array('%name' => $form_values['name'])));
return 'devel/variable';
Gerhard Killesreiter
committed
}
/**
* Menu callback: display the session.
*/
function devel_session() {
global $user;
$output = dprint_r($_SESSION, TRUE);
$output .= session_name(). '='. $user->sid;
return $output;
* Switch from original user to another user and back.
*
* Note: taken from mailhandler.module.
*
* Note: You first need to run devel_switch_user without
* argument to store the current user. Call devel_switch_user
* without argument to set the user back to the original user.
*
* @param $name The username to switch to.
function devel_switch_user($name = NULL) {
global $user;
static $orig_user = array();
if (isset($name)) {
$user = user_load(array('name' => $name));
}
// Retrieve the initial user. Can be called multiple times.
else if (count($orig_user)) {
$user = array_shift($orig_user);
array_unshift($orig_user, $user);
// Store the initial user.
else {
$orig_user[] = $user;
}
drupal_goto();
Moshe Weitzman
committed
* Menu callback; prints the loaded structure of the current node/user.
Moshe Weitzman
committed
function devel_load_object($type, $id) {
$output = '';