Same name and namespace in other branches
  1. 7.x-3.x includes/handlers.inc \views_join

A function class to represent a join and create the SQL necessary to implement the join.

This is the Delegation pattern. If we had PHP5 exclusively, we would declare this an interface.

Extensions of this class can be used to create more interesting joins.

join definition

  • table: table to join (right table)
  • field: field to join on (right field)
  • left_table: The table we join to
  • left_field: The field we join to
  • type: either LEFT (default) or INNER
  • extra: Either a string that's directly added, or an array of items:
  • - table: if not set, current table; if NULL, no table. This field can't be set in the cached definition because it can't know aliases; this field can only be used by realtime joins.
  • - field: Field or formula
  • - operator: defaults to =
  • - value: Must be set. If an array, operator will be defaulted to IN.
  • - numeric: If true, the value will not be surrounded in quotes.
  • - raw: If you specify raw the value will be used as it is, so you can have field to field conditions.
  • extra type: How all the extras will be combined. Either AND or OR. Defaults to AND.

Hierarchy

Expanded class hierarchy of views_join

Related topics

1 string reference to 'views_join'
node_views_data in modules/node.views.inc
Implementation of hook_views_data()

File

includes/handlers.inc, line 1582
handlers.inc Defines the various handler objects to help build and display views.

View source
class views_join {
  var $table = NULL;
  var $left_table = NULL;
  var $left_field = NULL;
  var $field = NULL;
  var $extra = NULL;
  var $type = NULL;
  var $definition = array();

  /**
   * Construct the views_join object.
   */
  function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
    $this->extra_type = 'AND';
    if (!empty($table)) {
      $this->table = $table;
      $this->left_table = $left_table;
      $this->left_field = $left_field;
      $this->field = $field;
      $this->extra = $extra;
      $this->type = strtoupper($type);
    }
    else {
      if (!empty($this->definition)) {

        // if no arguments, construct from definition.
        // These four must exist or it will throw notices.
        $this->table = $this->definition['table'];
        $this->left_table = $this->definition['left_table'];
        $this->left_field = $this->definition['left_field'];
        $this->field = $this->definition['field'];
        if (!empty($this->definition['extra'])) {
          $this->extra = $this->definition['extra'];
        }
        if (!empty($this->definition['extra type'])) {
          $this->extra_type = strtoupper($this->definition['extra type']);
        }
        $this->type = !empty($this->definition['type']) ? strtoupper($this->definition['type']) : 'LEFT';
      }
    }
  }

  /**
   * Build the SQL for the join this object represents.
   */
  function join($table, &$query) {
    if (empty($this->definition['table formula'])) {
      $right_table = "{" . $this->table . "}";
    }
    else {
      $right_table = $this->definition['table formula'];
    }
    if ($this->left_table) {
      $left = $query
        ->get_table_info($this->left_table);
      $left_field = "{$left['alias']}.{$this->left_field}";
    }
    else {

      // This can be used if left_field is a formula or something. It should be used only *very* rarely.
      $left_field = $this->left_field;
    }
    $output = " {$this->type} JOIN {$right_table} {$table['alias']} ON {$left_field} = {$table['alias']}.{$this->field}";

    // Load query tokens replacements.
    $view = views_get_current_view();
    $replacements = array();
    if (!empty($view)) {
      $replacements = $view
        ->substitutions();
    }
    else {
      vpr('The current view is not set, maybe some code missed to execute $view->pre_execute()');
    }

    // Tack on the extra.
    if (isset($this->extra)) {
      if (is_array($this->extra)) {
        $extras = array();
        foreach ($this->extra as $info) {
          $extra = '';

          // Figure out the table name. Remember, only use aliases provided
          // if at all possible.
          $join_table = '';
          if (!array_key_exists('table', $info)) {
            $join_table = $table['alias'] . '.';
          }
          elseif (isset($info['table'])) {
            $join_table = $info['table'] . '.';
          }

          // Apply query token replacements.
          $info['value'] = str_replace(array_keys($replacements), $replacements, $info['value']);

          // And now deal with the value and the operator.  Set $q to
          // a single-quote for non-numeric values and the
          // empty-string for numeric values, then wrap all values in $q.
          if (empty($info['raw'])) {
            $raw_value = $this
              ->db_safe($info['value'], $info);
            $q = empty($info['numeric']) ? "'" : '';
          }
          else {
            $raw_value = $info['value'];
            $q = '';
          }
          if (is_array($raw_value)) {
            $operator = !empty($info['operator']) ? $info['operator'] : 'IN';

            // Transform from IN() notation to = notation if just one value.
            if (count($raw_value) == 1) {
              $value = $q . array_shift($raw_value) . $q;
              $operator = $operator == 'NOT IN' ? '!=' : '=';
            }
            else {
              $value = "({$q}" . implode("{$q}, {$q}", $raw_value) . "{$q})";
            }
          }
          else {
            $operator = !empty($info['operator']) ? $info['operator'] : '=';
            $value = "{$q}{$raw_value}{$q}";
          }
          $extras[] = "{$join_table}{$info['field']} {$operator} {$value}";
        }
        if ($extras) {
          if (count($extras) == 1) {
            $output .= ' AND ' . array_shift($extras);
          }
          else {
            $output .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
          }
        }
      }
      else {
        if ($this->extra && is_string($this->extra)) {
          $output .= " AND ({$this->extra})";
        }
      }
    }
    return $output;
  }

  /**
   * Ensure that input is db safe. We only check strings and ints tho
   * so something that needs floats in their joins needs to do their
   * own type checking.
   */
  function db_safe($input, $info) {
    if (is_array($input)) {
      $output = array();
      foreach ($input as $value) {
        if (empty($info['numeric'])) {
          $output[] = db_escape_string($value);
        }
        else {
          $output[] = intval($value);
        }
      }
    }
    else {
      if (empty($info['numeric'])) {
        $output = db_escape_string($input);
      }
      else {
        $output = intval($input);
      }
    }
    return $output;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
views_join::$definition property
views_join::$extra property
views_join::$field property
views_join::$left_field property
views_join::$left_table property
views_join::$table property
views_join::$type property
views_join::construct function Construct the views_join object.
views_join::db_safe function Ensure that input is db safe. We only check strings and ints tho so something that needs floats in their joins needs to do their own type checking.
views_join::join function Build the SQL for the join this object represents.