You are here

tool.inc in Coder 7.2

Same filename and directory in other branches
  1. 7 coder_upgrade/conversions/tool.inc

Provides tools to assist with conversion routines.

These routines use the grammar parser and are version-agnostic with respect to Drupal. An exception may be coder_upgrade_convert_op() which helps with hook($op) style functions, many (or all?) of which were eliminated in Drupal 7.x. However, this pattern may remain in contributed modules.

Copyright 2009-11 by Jim Berry ("solotandem", http://drupal.org/user/240748)

File

coder_upgrade/conversions/tool.inc
View source
<?php

/**
 * @file
 * Provides tools to assist with conversion routines.
 *
 * These routines use the grammar parser and are version-agnostic with respect
 * to Drupal. An exception may be coder_upgrade_convert_op() which helps
 * with hook($op) style functions, many (or all?) of which were eliminated in
 * Drupal 7.x. However, this pattern may remain in contributed modules.
 *
 * Copyright 2009-11 by Jim Berry ("solotandem", http://drupal.org/user/240748)
 */

/**
 * Initiates the transformation of a hook($op) to a new hook_$op style function.
 *
 * @param PGPNode $node
 *   A node object containing a PGPClass (or function) item.
 * @param string $callback
 *   A string of the callback function for the hook.
 * @param integer $op_index
 *   An integer of the operation parameter in the function parameter list.
 */
function coder_upgrade_convert_op(&$node, $callback, $op_index) {
  cdp("inside " . __FUNCTION__);
  cdp("{$callback}");

  /*
   * DBTNG changes can be done in another routine
   */

  // Get the function object.
  $item =& $node->data;

  // Rename the function in case any code is left over.
  $item->name .= '_OLD';

  // Get the operation variable from the function parameter at index $op_index.
  // This function removes any default value assignment (e.g. $op = 'list') or
  // inline comments included in the parameter expression.
  if (!($variable = $item
    ->getParameterVariable($op_index))) {
    clp("ERROR: Variable not found in hook(\$op) parameter {$op_index}");
    return;
  }
  $op = $variable
    ->toString();

  // Get the function body statements.
  $body =& $item->body;

  /*
   * Two likely cases: switch statement or series of if blocks.
   * Compare the $op_index parameter to the function with the switch operand.
   */

  // Loop on the body statements looking for the $op variable in an IF or
  // SWITCH condition.
  $current = $body
    ->first();
  while ($current->next != NULL) {
    $found = FALSE;
    $statement =& $current->data;
    if ($statement instanceof PGPConditional) {

      //      cdp("inside PGPConditional check");
      //      cdp("statement->type = " . $statement->type);
      if ($statement->type == T_SWITCH) {

        //        cdp("inside T_SWITCH check");
        // Get the list of conditions.
        $conditions = $statement->conditions;

        // Get the first condition. (With a switch there should only be one condition.)
        $condition = $conditions
          ->getElement()
          ->findNode('operand')
          ->stripComments();
        $operand = $condition
          ->toString();

        // If the condition variable matches the $op variable, then go to work.
        if ($op == $operand) {
          $found = TRUE;
          $cases = $statement->body;
          $node
            ->traverse($cases, $callback);
        }
      }
      elseif (in_array($statement->type, array(
        T_IF,
        T_ELSEIF,
        T_ELSE_IF,
      ))) {
        cdp("inside T_IF check");

        /*
         * Extract the conditions referencing the $op variable and loop on them.
         * These are conditions of the form $op == 'operation'.
         * Replace them with condition of TRUE to not disrupt the logic.
         * Retain any other conditions as part of the body in the new hook
         * function.
         */
        $operations = coder_upgrade_extract_operations($statement->conditions, $op);

        // Loop on the extracted operations.
        foreach ($operations as $operation) {
          $found = TRUE;

          // Change a T_ELSEIF to a T_IF in the new hook function.
          $statement->type = T_IF;

          // If it isn't already.
          $block = new stdClass();
          $block->body = new PGPBody();
          $block->body
            ->insertLast($statement);
          $case_node = new PGPNode($block, $current->container);

          // TODO What is the correct container???
          $callback($node, $case_node, $operation);
        }
      }
    }
    elseif (is_array($statement) && $statement['type'] == T_WHITESPACE) {

      // Remove whitespace.
      $found = TRUE;
    }

    // Move to next node.
    $current =& $current->next;
    if ($found) {

      // Get the statement list the switch statement (or if block) node is part of.
      $container =& $current->container;
      $container
        ->delete($current->previous);
    }
  }
  if ($body
    ->count()) {
    $editor = PGPEditor::getInstance();

    // TODO Insert comment indicating the block was not changed.
    $body
      ->insertFirst($editor
      ->commentToStatement('// TODO Remaining code in this function needs to be moved to the appropriate new hook function.'));
  }
}

/**
 * Extracts operations from conditions and replaces the conditions with TRUE.
 *
 * @param PGPList $conditions
 *   A list of conditions to an if block.
 * @param string $op
 *   A string of the hook operation.
 *
 * @return array
 *   Array of operations referenced in the if block.
 */
function coder_upgrade_extract_operations(&$conditions, $op) {
  cdp("inside " . __FUNCTION__);
  $operations = array();

  /*
   * A condition may consist of at most two operands separated by an operator.
   */
  if ($conditions instanceof PGPList) {

    // Iterate over the conditions of the condition list.
    $current = $conditions
      ->first();
    while ($current->next != NULL) {
      $type = $current->type;
      if ($type == 'condition') {

        // Get the condition object of the current node.
        $condition =& $current->data;

        // Iterate over elements of the condition expression.
        $found = FALSE;
        $current2 = $condition
          ->first();
        while ($current2->next != NULL) {
          if ($current2->type == 'operand') {

            // Get the operand (object or array) of the current node.
            $element =& $current2->data;

            // Inspect the element looking for $op.
            if ($element instanceof PGPOperand) {

              // Inspect the operand looking for $op.
              $text = $element
                ->toString();
              if (strpos($text, $op) !== FALSE) {
                $found = TRUE;
              }
              else {
                $operation = $element
                  ->toString();
              }
            }
            elseif (is_array($element)) {

              // This should have type = T_CONSTANT_ENCAPSED_STRING.
              $operation = $element['value'];
            }
          }

          // An interesting effect takes place with an & on the next line.
          $current2 = $current2->next;
        }
        if ($found) {

          // Replace condition with TRUE so the logic remains the same.
          $condition
            ->clear();
          $data = array(
            'type' => T_STRING,
            'value' => 'TRUE',
          );
          $condition
            ->insertLast($data, 'operand');

          // Add operation to list.
          $operations[] = trim($operation, "'\"");
        }
      }
      $current = $current->next;
    }
  }
  return $operations;
}

/**
 * Creates hook_$op function from the case (or if) block of an $op-style hook.
 *
 * @param PGPNode $node
 *   A node object containing a PGPClass (or function) item.
 * @param PGPNode $case_node
 *   A node object containing a PGPCase item.
 * @param string $hook
 *  A string of the new function name.
 * @param array $parameters
 *  An array of function parameters.
 */
function coder_upgrade_op_to_hook($node, $case_node, $hook, $parameters) {

  /*
   * Copy the case body to the new hook function.
   * Insert before (or after) the $item function.
   *
   * When case body is empty (e.g. insert, update), then use next reference
   * until a non-empty body is found.
   *
   * TODO
   * Add the new function to the list of functions.
   * This is useful when we may need to check for the existence of a function
   * on another upgrade.
   * Example: hook_link() becomes part of hook_node_view()
   * or hook_comment_view() based on $type parameter. Also hook_link_alter()
   * code goes in hook_node_view_alter() or hook_comment_view_alter().
   * See http://drupal.org/node/224333#node_links.
   */
  global $_coder_upgrade_module_name;
  $case =& $case_node->data;

  // Set values for the new hook function.
  $comment = array(
    'type' => T_DOC_COMMENT,
    'value' => "/**\n * Implements hook{$hook}().\n */",
  );
  $name = $_coder_upgrade_module_name . $hook;

  // Create the new hook function.
  $function = new PGPClass($name);
  $function->comment = $comment;
  $function->type = T_FUNCTION;
  $function->parameters = new PGPList();

  // Use the editor to set the function parameters.
  $editor = PGPEditor::getInstance();
  $editor
    ->setParameters($function, $parameters);

  // Copy the case (or if) block as the body of the function.
  $function->body = $case->body;
  if ($function->body
    ->isEmpty()) {

    // Find the next case with a body.
    $case_node2 = $case_node->next;
    while ($case_node2->next != NULL) {
      $case2 = $case_node2->data;
      $body2 = $case2->body;
      if (!$body2
        ->isEmpty()) {
        $function->body = $case2->body;
        break;
      }
      $case_node2 = $case_node2->next;
    }
  }

  // Remove the break statement from a case block.
  if ($break = $function->body
    ->find(T_BREAK, 'reverse', TRUE)) {
    cdp("return statement found in hook");
    $function->body
      ->delete($break);
  }

  // Remove any trailing blank lines (after break) that are included in body.
  $last = $function->body
    ->last();
  if (is_array($last->data) && $last->data['type'] == T_WHITESPACE) {
    cdp("YAHOO: found whitespace statement in hook_nodeapi");
    $function->body
      ->delete($last);
  }

  // Get the statement list the function node is part of.
  $container =& $node->container;

  // Insert the new function before the old function.
  $container
    ->insertBefore($node, $function, 'function');

  // Insert a blank line.
  $whitespace = array(
    'type' => T_WHITESPACE,
    'value' => 1,
  );
  $container
    ->insertBefore($node, $whitespace, 'whitespace');
}

/**
 * Initiates the transformation of array assignments in a hook.
 *
 * Applies to: hook_action_info(), hook_hook_info(), hook_node_info(), hook_theme().
 *
 * NOTE
 * In general, there are 3 typical cases (or code styles):
 * - return array('key1' => array('key2' => ...);
 * - $var = array('key1' => array('key2' => ...); return $var;
 * - $var = array(); $var['key1'] = array('key2' => ...); return $var;
 *
 * The inner array to modify is 3 levels deep in the first 2 cases, but only
 * 2 levels deep in the third. In the first 2 cases, we can loop on the key1
 * arrays. In the third, the loop is on assignment statements.
 *
 * This new routine was failing on hook_hook_info() because the keys are not
 * distinguishable. Ie, we can not tell what level of the array we are on if
 * the array is inline and has 3 levels. Previously, return_case1() would strip
 * off the first layer and get to the second level. There is no guarantee of
 * nice code anyway.
 *
 * This new routine was failing on capturing drupal_get_form() callbacks
 * on case 5, like example_admin_form3() defined in
 * $items[$admin_path]['page arguments'][] = 'example_admin_form3'. This again
 * relates to a depth parameter and that we are always looking for an array.
 *
 * Should we pass a depth parameter, or figure it dynamically?
 *
 * @param PGPList $body
 *   List of statements in a block.
 * @param string $hook
 *   Name of the hook being modified.
 * @param string $callback
 *   A string of the callback function for the hook.
 * @param integer $start_depth
 *   The starting depth of nested arrays to traverse.
 * @param integer $remaining_depth
 *   The remaining depth of nested arrays to traverse. When equal to zero, stop.
 */
function coder_upgrade_convert_return(&$body, $hook, $callback = '', $start_depth = 0, $remaining_depth = -1) {

  // DONE
  cdp("inside " . __FUNCTION__);

  // Initialize.
  $editor = PGPEditor::getInstance();
  $callback = $callback == '' ? "coder_upgrade_callback_{$hook}" : $callback;
  $msg = '// TODO The array elements in this hook function need to be changed.';

  // Get a list of return statements in the body statements.
  $nodes = $body
    ->searchAll('PGPFunctionCall', 'name', 'value', 'return', TRUE);

  // Keep track of return variables to avoid redundant searching.
  $already_searched = array();
  while (!empty($nodes)) {
    cdp('while (!empty($nodes)) ' . __FUNCTION__);
    $return_node = array_shift($nodes);
    $return = $return_node->data;

    // Evaluate the return operand.
    if (get_class($return) == 'PGPFunctionCall') {
      $value = $return
        ->getParameter();
      $depth = 0;
    }
    elseif (get_class($return) == 'PGPAssignment') {

      // Get the operands to the right of the assignment operator.
      $value = $return
        ->getValue();
      cdp($return
        ->toString(), '$return AFTER');

      // Evaluate the "depth" of the assignment based on number of indices in
      // the assignment variable.
      // Examples: the operand on the RHS is at
      //   level 1: $var = array(key => array(..), ..)
      //   level 2: $var[key1] = array(..)
      //   level 3: $var[key1][key2] = array(..)
      // This mimics what was done in return_caseN(). We went down to level 2
      // from case1 to case3.
      $assign_variable = $return->values
        ->getElement()
        ->getType('operand')
        ->stripComments();

      // @todo This should handle most cases, but will fail depending on code style.
      // If depth is > start_depth (like case5), then reconstruct an array at
      // the desired depth using toString() and reparsing (see case5).
      $depth = $assign_variable
        ->countType('index');
      if ($depth > $start_depth) {

        // @todo This works in some use cases (menu stuff in begin.inc). If we
        // need to change the original expression, this fails because $value is
        // now disjoint from the original expression.
        $value = coder_upgrade_reconstruct_array($assign_variable, $value);
        $depth = 1;

        // $assign_variable->countType('index');
      }
    }
    cdp($value
      ->toString(), '$value');
    $occurrence = 1;

    // Loop on all operands in expression (e.g. $array + array(..)).
    while ($occurrence < $value
      ->countType('operand') + 1) {
      $operand = $value
        ->getType('operand', $occurrence);
      if ($operand) {
        cdp('inside if ($operand)');
        if (!is_object($operand)) {

          // @todo This hits stuff like $items[$admin_path]['page arguments'][] = 'example_admin_form3';
          cdp('!is_object($operand)');
          cdp($operand, '$operand');
          $occurrence++;
          continue;
        }
        cdp($operand
          ->toString(), '$operand');
        if (get_class($operand) == 'PGPArray') {

          // Use case 1 - returns array directly.
          $operand
            ->traverse2($return_node, $hook, $callback, $start_depth - $depth, $remaining_depth);
        }
        elseif (get_class($operand) == 'PGPOperand') {

          // Avoid redundant searching.
          if (in_array($operand
            ->stripComments()
            ->toString(), $already_searched)) {
            $occurrence++;
            continue;
          }

          /*
           * Search body statements for all assignments to the return variable.
           * The assignment could be to an array element like $info['node_type_name'] = array(...).
           * Or directly to the variable like $info = array('node_type_name' => array(...)).
           */
          $already_searched[] = $return_variable = $operand
            ->stripComments()
            ->toString();

          // @todo Limit search to nodes preceding the statement.
          $nodes = array_merge($nodes, $body
            ->searchAll('PGPAssignment', 'values', 0, $return_variable, TRUE));
        }
        else {

          // @todo This message is not accurate -- this error hits on the array value being a string or function call.
          clp("ERROR: operand of return statement is not an array or variable in hook_{$hook}");
          cdp("ERROR: operand of return statement is not an array or variable in hook_{$hook}");
          cdp($operand, '$operand');
          $body
            ->insertFirst($editor
            ->commentToStatement($msg), 'comment');
        }
      }
      $occurrence++;
    }
  }
}

/**
 * Returns array with another level whose key is from assignment variable.
 *
 * @param PGPExpression $variable
 *   The assignment variable (left of assignment operator).
 * @param PGPExpression $value
 *   The assignment value (right of assignment operator).
 *
 * @return PGPExpression
 *   The new array expression.
 */
function coder_upgrade_reconstruct_array($variable, $value) {
  cdp("inside " . __FUNCTION__);
  if ($variable
    ->countType('index') < 2) {
    return new PGPExpression();
  }
  $editor = PGPEditor::getInstance();

  // This routine assumes the second index is the one to be reconstructed.
  $key = trim($variable
    ->getType('index', 2)
    ->toString(), "'\"");
  $array = $editor
    ->expressionToStatement("array('{$key}' => {$value->toString()})");

  //->getElement();
  cdp($array
    ->toString(), '$array');
  return $array;

  /*
    // The above works well for existing use cases, but fails for hook_perm possibly
    // because the array traverse2() routine will skip the key when $depth != $start_depth.
    $count = $variable->countType('index');
    if (!$count) {
      return new PGPExpression();
    }

    $editor = PGPEditor::getInstance();

    // Allow for a key being a string or a variable expression.
    $key = $variable->getType('index', $count)->toString(); // $key = trim($variable->getType('index', $count)->toString(), "'\"");
    if ($key) {
      $array = $editor->expressionToStatement("array($key => {$value->toString()})"); //->getElement();
    }
    else {
      $array = $editor->expressionToStatement("array({$value->toString()})"); //->getElement();
    }
    cdp($array->toString(), '$array');
    return $array;
  */
}

/**
 * Initiates the transformation of array assignments in a hook.
 *
 * Applies to: hook_action_info(), hook_hook_info(), hook_node_info(), hook_theme().
 *
 * NOTE
 * In general, there are 3 typical cases (or code styles):
 * - return array('key1' => array('key2' => ...);
 * - $var = array('key1' => array('key2' => ...); return $var;
 * - $var = array(); $var['key1'] = array('key2' => ...); return $var;
 *
 * The inner array to modify is 3 levels deep in the first 2 cases, but only
 * 2 levels deep in the third. In the first 2 cases, we can loop on the key1
 * arrays. In the third, the loop is on assignment statements.
 *
 */
function coder_upgrade_convert_return_OLD(&$node, $hook, $callback = '') {

  // DONE
  cdp("inside " . __FUNCTION__);
  $editor = PGPEditor::getInstance();
  $msg = '// TODO The array elements in this hook function need to be changed.';
  $item =& $node->data;

  // Get the function body.
  $body =& $item->body;
  if (!($return = $body
    ->find(T_RETURN, 'reverse'))) {
    clp("ERROR: return statement not found in hook_{$hook}");
    $body
      ->insertFirst($editor
      ->commentToStatement($msg), 'comment');
    return;
  }
  $value =& $return
    ->getParameter();

  // @todo Strip comments.
  // Examine the type of the operand in the return statement.
  $operand = $value
    ->getElement();
  if (get_class($operand) == 'PGPArray') {

    // Use case 1 - returns array directly.
    // The keys of this array are the node type items.
    $array1 = $value
      ->getElement();
    coder_upgrade_callback_return_case1($array1, $hook, $callback);
  }
  elseif (get_class($operand) == 'PGPOperand') {

    /*
     * Loop on body statements until we find an assignment to the return variable.
     * The assignment could be to an array element like $info['node_type_name'] = array(...).
     * Or directly to the variable like $info = array('node_type_name' => array(...)).
     */
    $return_variable = $operand
      ->toString();
    $count = 0;
    coder_upgrade_convert_return_loop_OLD($body
      ->first(), $count, $return_variable, $hook, $callback);
    if (!$count) {
      clp("ERROR: assignment statement to return variable not found in hook_{$hook}");
      $body
        ->insertFirst($editor
        ->commentToStatement($msg), 'comment');
      return;
    }
  }
  else {
    clp("ERROR: operand of return statement is not an array or variable in hook_{$hook}");
    $body
      ->insertFirst($editor
      ->commentToStatement($msg), 'comment');
  }
}
function coder_upgrade_convert_return_loop_OLD(&$node, &$count, $return_variable, $hook, $callback = '') {

  // NOT DONE
  cdp("inside " . __FUNCTION__);
  is_object($node->data) ? cdp($node->data
    ->toString(), __FUNCTION__ . ' $node') : cdp($node->data, __FUNCTION__ . ' $node');

  /*
   * Loop on body statements until we find an assignment to the return variable.
   * The assignment could be to an array element like $info['node_type_name'] = array(...).
   * Or directly to the variable like $info = array('node_type_name' => array(...)).
   */
  $current = $node;
  while ($current->next != NULL) {
    if (is_object($current->data) && $current->data->type == T_ASSIGNMENT) {

      // if ($current->data->isType(T_ASSIGNMENT)) {
      $assignment = $current->data;
      $assign_variable = $assignment->values
        ->getElement()
        ->getElement()
        ->stripComments()
        ->toString();
      if ($return_variable == $assign_variable) {

        // Use case 2: makes one assignment to array variable; returns variable.
        cdp("Use case 2: Assignment variable matches return variable");

        /*
         * TODO This equality check would fail if comments are embedded between
         * variable and operator.
         * Example: $theme /**\/ = $array + array(..);
         */
        $value1 = $assignment->values
          ->getElement();

        /*
         * TODO Find the operand of class PGPArray.
         * Example: $theme /**\/ = $array + array(..);
         */
        $array1 = $value1
          ->getElement($value1
          ->count() - 1);
        if (!is_object($current->data) || get_class($array1) != 'PGPArray') {
          continue;
        }
        coder_upgrade_callback_return_case1($array1, $hook, $callback);
        $count++;
      }
      elseif (strpos($assign_variable, $return_variable) !== FALSE) {

        // Use case 3: makes multiple assignments to array variable; returns variable.
        cdp("Use case 3: Assignment variable includes return variable");

        /*
         * TODO This substring check would fail if comments are embedded between
         * variable and operator.
         * Example: $theme /**\/ = $array + array(..);
         */
        $assign_variable2 = $assignment->values
          ->getElement()
          ->getElement()
          ->stripComments();
        $value1 = $assignment->values
          ->getElement();
        if ($assign_variable2
          ->countType('index') == 1) {
          cdp('variable has one index');
          $array1 = $value1
            ->getElement($value1
            ->count() - 1);
          coder_upgrade_callback_return_case3($array1, $hook, $callback);
          $count++;
        }
        elseif ($assign_variable2
          ->countType('index') == 2) {
          cdp('variable has two indices');

          /*
           * TODO Use case 5
           * Assignment to array variable at an index
           * $items[$admin_path] = array_merge($default_menu_fields, $menu_item);
           * $items[$admin_path]['page callback'][] = 'example_admin_form';
           * We need to count the indices; check for last index == []
           * The second index is usually the item to be inspected
           */
          $key2 = $assign_variable2
            ->getType('index', 2);
          coder_upgrade_callback_return_case5($assignment, $hook, $callback);
        }
        elseif ($assign_variable2
          ->countType('index') == 3 && $assign_variable2
          ->getType('index', 3)
          ->toString() == '') {
          cdp('variable has three indices');

          /*
           * TODO Use case 5
           * Assignment to array variable at an index
           * $items[$admin_path] = array_merge($default_menu_fields, $menu_item);
           * $items[$admin_path]['page callback'][] = 'example_admin_form';
           * We need to count the indices; check for last index == []
           * The second index is usually the item to be inspected
           */
          $key2 = $assign_variable2
            ->getType('index', 2);
          coder_upgrade_callback_return_case5($assignment, $hook, $callback);
        }
        else {
          clp("ERROR: Assignment variable has more than three index levels");
          cdp("ERROR: Assignment variable has more than three index levels");
          cdp($assign_variable2
            ->getType('index', 3)
            ->toString());
        }
      }
    }
    elseif (is_object($current->data) && in_array(get_class($current->data), array(
      'PGPConditional',
      'PGPFor',
      'PGPForeach',
      'PGPCase',
    ))) {

      // elseif (is_a($current->data, 'PGPConditional')) {
      coder_upgrade_convert_return_loop($current->data->body
        ->first(), $count, $return_variable, $hook, $callback);
    }
    else {
      cdp('fell thru conditions in ' . __FUNCTION__);
      is_object($current->data) ? cdp($current->data
        ->toString(), __FUNCTION__ . ' $current') : cdp($current->data, __FUNCTION__ . ' $current');
    }
    $current = $current->next;
  }
}

/**
 * Loops on elements of first-level array.
 *
 * @todo Abstract to the PGPArray object: traverse with callback.
 * This is setting up as a nice recursive function.
 *
 * @param PGPArray $array1
 */
function coder_upgrade_callback_return_case1(&$array1, $hook, $callback = '') {

  // DONE
  cdp("inside " . __FUNCTION__);

  // The keys of this array are the node types.
  if (!$array1 instanceof PGPArray) {
    clp("ERROR: array1 is not a PGPArray object in hook_{$hook}");
    return;
  }

  // Grab the PGPList of values.
  $values1 = $array1->values;
  $current1 = $values1
    ->first();
  while ($current1->next != NULL) {
    if ($current1->type == 'key') {
      $key1 = $current1->data;

      // Do something if appropriate.
      // This is not the one needed; we need the next level down.
    }
    elseif ($current1->type == 'value') {

      // This is the value expression for a node type key.
      $value1 = $current1->data;
      if (get_class($value1) != 'PGPExpression') {
        clp("ERROR: value1 is not a PGPExpression object in hook_{$hook}");
        return;
      }

      // This is the array of node type items.
      $array2 = $value1
        ->getElement();
      coder_upgrade_callback_return_case3($array2, $hook, $callback);
    }
    $current1 = $current1->next;
  }
}

/**
 * Loops on elements of second-level array.
 *
 * @todo Abstract to the PGPArray object: traverse with callback.
 *
 * @param PGPArray $array2
 */
function coder_upgrade_callback_return_case3(&$array2, $hook, $callback = '') {

  // DONE
  cdp("inside " . __FUNCTION__);
  $callback = $callback == '' ? "coder_upgrade_callback_{$hook}" : $callback;

  // The keys of this array are the node type items.
  if (!$array2 instanceof PGPArray) {
    clp("ERROR: array2 is not a PGPArray object in hook_{$hook}");
    cdp("ERROR: array2 is not a PGPArray object in hook_{$hook}");
    cdp($array2);
    return;
  }

  // Grab the PGPList of values.
  $values2 = $array2->values;
  $key2 = '';
  $current2 = $values2
    ->first();
  while ($current2->next != NULL) {
    if ($current2->type == 'key') {
      $key2 = trim($current2->data
        ->toString(), "'\"");
      $callback($array2, $current2, $hook, $current2->type, $key2, NULL);
    }
    elseif ($current2->type == 'value') {
      $value2 = trim($current2->data
        ->toString(), "'\"");
      $callback($array2, $current2, $hook, $current2->type, $key2, $value2);
      $key2 = '';

      // Clear key in case not all elements have keys.
    }
    $current2 = $current2->next;
  }
}
function coder_upgrade_callback_return_case5($assignment, $hook, $callback = '') {

  // NOT DONE
  cdp("inside " . __FUNCTION__);

  /*
   * TODO Convert the assignment into an array expression. Then pass off the
   * array to coder_upgrade_callback_return_case3.
   *
   * Loop on assignment to remove all nodes up to and including the assignment
   * operator. Grab the second index from the first node. Then toString() and
   * build an array with the second index as the key.
   */
  $assign_variable2 = $assignment->values
    ->getElement()
    ->getElement()
    ->stripComments();
  $key2 = $assign_variable2
    ->getType('index', 2);
  if ($assignment->values
    ->getElement()
    ->get(1)->type != 'assign') {
    clp("ERROR: second element of assignment is not the assignment operator");
    return;
  }
  $editor = PGPEditor::getInstance();

  // Remove the assignee and the assignment operator.
  $assignment = $assignment->values
    ->getElement();
  $assignment
    ->deleteElement();
  $assignment
    ->deleteElement();
  $temp = $assignment;

  //->values->getElement()->getElement(2); // ->stripComments();
  $key = trim($key2
    ->toString(), "'\"");
  $array2 = $editor
    ->expressionToStatement("array('{$key}' => {$temp->toString()})")
    ->getElement();
  coder_upgrade_callback_return_case3($array2, $hook, $callback);
}

Functions

Namesort descending Description
coder_upgrade_callback_return_case1 Loops on elements of first-level array.
coder_upgrade_callback_return_case3 Loops on elements of second-level array.
coder_upgrade_callback_return_case5
coder_upgrade_convert_op Initiates the transformation of a hook($op) to a new hook_$op style function.
coder_upgrade_convert_return Initiates the transformation of array assignments in a hook.
coder_upgrade_convert_return_loop_OLD
coder_upgrade_convert_return_OLD Initiates the transformation of array assignments in a hook.
coder_upgrade_extract_operations Extracts operations from conditions and replaces the conditions with TRUE.
coder_upgrade_op_to_hook Creates hook_$op function from the case (or if) block of an $op-style hook.
coder_upgrade_reconstruct_array Returns array with another level whose key is from assignment variable.