devel_helper.module

<?php
// $Id$

/**
 * @file
 * Devel add-on module that outputs a themer friendly alternative to dprint_r, dpr, and dvm.
 *
 * This module generates a prettier and friendlies output for the dprint_r() function that 
 * allows themers and developers to cut-n-paste the displayed variable references.
 * Long strings of text and (x)html are also suppressed to insure that the output is read-able.
 * Finally, themers and developers can control the number of nested arrays and objects to 
 * be displayed and then toggle open and close the arrays or objects they wish to examine.
 *
 * @code
 * // Basic examples
 * dprx($variables);
 * // This generate an output that initially display 3 levels of data.
 * dprx($variables, 3);
 * // This is the recommended format for the value parameter.
 * // By passing in the variable name ($variables) into dprint_rx()
 * // the output will contain the full PHP string for every variable.
 * dprx(array('$variables' => $variables));@endcode
 *
 * Learn more about the dprint_rx() function and view an example at my website 
 * @link http://thebigbluehouse.com/printr-not-pretty http://thebigbluehouse.com/printr-not-pretty @endlink.
 *
 * Notes
 * - Loosely based on contemplates contemplate_array_variables() recursion.
 * - Style and color scheme is based on the output from ColdFusion's <CFDUMP> tag.
 * 
 * Related/Similar modules
 * - @link http://krumo.kaloyan.info/ Krumo @endlink
 */

/**
 * Print a variable in a friendly and usable format to the page.
 *
 * @param $value
 *   Value to be displayed
 * @param $expand
 *   Number of levels to be initially expanded
 * @param $return
 *   TRUE will return the output and FALSE will print the output
 */
function dprint_rx($value, $expand = 1, $return = FALSE) {
  // This recursion limit could be set from a settings page but 9 seems like a reasonable level.
  $recursion_limit = 9;

  // Get type
  $type = gettype($value);

  // Cast object as array
  $value = (array)$value;

  $output = '';
  if ($type == 'array' || $type == 'object') { // Recurse

    // Get path
    $base_path = base_path();
    $path = drupal_get_path('module', 'devel_helper');
    // Load css and js the drupal way but if the page is not fully rendered the css and js is added below.
    drupal_add_css($path .'/dprx.css', 'module');
    drupal_add_js($path .'/dprx.js', 'module');

    // CSS and JS will be directly embedded to insure they are loaded even if the output is not rendered inside a drupal template.
    // This code would only be loaded when someone calls dprint_rx(); and then exit(); 
    // or they call dprx() within the templatepage.tpl.php which has already loaded the css and js.
    // NOTE: This approach is not valid xhtml but it allows the needed css and js to remain in external files.
    
    
    // Check for jQuery and Drupal
    $output .= '<script type="text/javascript">';
    $output .= 'if(!window.jQuery){document.write(\'<\' + \'script type="text/javascript" src="'. $base_path .'misc/jquery.js"></\' + \'script>\');}';
    $output .= 'if(!window.Drupal){document.write(\'<\' + \'script type="text/javascript" src="'. $base_path .'misc/drupal.js"></\' + \'script>\');}';
    $output .= '</script>';
    
    // Check for initDevelHelper behavior. If it is not loaded assume the css is missing
    $output .= '<script type="text/javascript">';
    $output .= 'if(!Drupal.behaviors.initDevelHelper){';
    $output .= 'document.write(\'<link type="text/css" rel="stylesheet" media="all" href="'. $base_path . $path .'/dprx.css" />\');';
    $output .= 'document.write(\'<\' + \'script type="text/javascript" src="'. $base_path . $path .'/dprx.js"></\' + \'script>\');';
    $output .= '}</script>';

    // Look for a variable names, beginning with $, in the value's keys then output them separately.
    $keys = array_keys($value);
    foreach ($keys as $arr_key) {
      if (strpos($arr_key, '$') === 0) {
        $output .= '<div class="dprx">';
        $output .= _dprint_rx_recurse($value[$arr_key], $arr_key, $expand, 0, $recursion_limit);
        $output .= '</div>';
        // Remove the value
        unset($value[$arr_key]);
      }
    }

    // If $value still contains items then output the data.
    if (count($value)) {
      $output .= '<div class="dprx">';
      $output .= _dprint_rx_recurse($value, FALSE, $expand, 0, $recursion_limit);
      $output .= '</div>';
    }

  }
  else { // A single item
    $output .= '<pre class="dprx">'. var_export($value, TRUE) .'</pre>';
  }

  if ($return) {
    return $output;
  }
  else {
    print($output);
  }
}

/**
 * Shortcut alias for dprint_rx().
 */
function dprx($value, $expand = 1) {
  dprint_rx($value, $expand);
}

/**
 * Print a variable in a friendly and usable format to the 'message' area of the page. Uses drupal_set_message()
 */
function dvmx($value, $expand = 1) {
  drupal_set_message( dprint_rx($value, $expand, TRUE) );
}

/**
 * Recurses a variable to generate a friendly and usable format to be displayed by dprint_rx(), dprx(), and dvmx().
 */
function _dprint_rx_recurse($value, $key, $expand, $depth, $recursion_limit) {
  // Check recursion limit
  if ($depth >= $recursion_limit) {
    return '';
  }

  // Get type
  $type = gettype($value);

  // Cast object to array
  $value = (array)$value;

  // Set css class dprx-{type} and whether expanded closed.
  $output .= '<div class="dprx-'. $type . (($depth >= $expand)?' dprx-closed':'') .'">'; // start .dprx-{type}-item

  // Array and object title
  $output .= '<div class="dprx-title dprx-'. $type .'-title">'; // start .dprx-{type}-title
  $output .= ($key !== '' && $key !== FALSE) ? $key .' = ' : '';
  $output .= (($type == 'array') ? 'array()':'new stdClass()') .';';
  $output .= '</div>';

  $output .= '<div class="dprx-'. $type .'-value">';

  // Loop the arrays and (array)objects.
  foreach ($value as $arr_key => $arr_value) {

    // Format $key with object or array syntax
    if ($key) {
      if ($type == 'object') {
        $arr_key = $key .'->'. $arr_key;
      }
      else {
        $arr_key = $key . ((is_int($arr_key)) ? '['. $arr_key .']':'[\''. $arr_key .'\']');
      }
    }

    if (is_array($arr_value) || is_object($arr_value)) {
      // Recurse through objects and arrays
      $output .= _dprint_rx_recurse($arr_value, $arr_key, $expand, $depth+1, $recursion_limit);
    }
    else {
      // Display other data types
      $arr_type = gettype($arr_value);
      $output .= "<div>";
      if ($arr_type == 'string' && ($len = drupal_strlen($arr_value)) > 40) {
        $output .= $arr_key .' <span>=</span> <a title="'. htmlspecialchars( print_r($arr_value, TRUE) ) .'">{string:'. $len .'}</a>';
      }
      else if ($arr_type == 'boolean') {
        $output .= $arr_key .'<span> = '. (($arr_value ? 'TRUE' : 'FALSE')) .';</span>';
      }
      else {
        $output .= $arr_key .'<span> = '. var_export($arr_value, TRUE) .';</span>';
      }
      $output .= "</div>";

    }
  }

  $output .= '</div>'; // close .dprx-{type}-value

  $output .= '</div>'; // close .dprx-{type}-item

  return $output;
}