You are here

class JoinPluginBase in Views (for Drupal 7) 8.3

Represents a join and creates the SQL necessary to implement the join.

@todo It might make sense to create an interface for joins.

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

Hierarchy

Expanded class hierarchy of JoinPluginBase

Related topics

4 files declare their use of JoinPluginBase
JoinTest.php in lib/Drupal/views/Tests/Plugin/JoinTest.php
Definition of Drupal\views\Tests\Plugin\JoinTest.
JoinTest.php in tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/join/JoinTest.php
Definition of Drupal\views_test_data\views\join\JoinTest.
QueryTest.php in tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/query/QueryTest.php
Definition of Drupal\views_test_data\Plugin\views\query\QueryTest.
Sql.php in lib/Drupal/views/Plugin/views/query/Sql.php
Definition of Drupal\views\Plugin\views\query\Sql.

File

lib/Drupal/views/Plugin/views/join/JoinPluginBase.php, line 53
Definition of Drupal\views\Plugin\views\join\JoinPluginBase.

Namespace

Drupal\views\Plugin\views\join
View source
class JoinPluginBase extends PluginBase {

  /**
   * The table to join (right table).
   *
   * @var string
   */
  public $table;

  /**
   * The field to join on (right field).
   *
   * @var string
   */
  public $field;

  /**
   * The table we join to.
   *
   * @var string
   */
  public $leftTable;

  /**
   * The field we join to.
   *
   * @var string
   */
  public $leftField;

  /**
   * An array of extra conditions on the join.
   *
   * Each condition is either a string that's directly added, or an array of
   * items:
   *   - table(optional): If not set, current table; if NULL, no table. If you
   *     specify a table in cached configuration, Views will try to load from an
   *     existing alias. If you use realtime joins, it works better.
   *   - field(optional): Field or formula. In formulas we can reference the
   *     right table by using %alias.
   *   - operator(optional): The operator used, 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.
   *
   * @see SelectQueryInterface::addJoin()
   *
   * @var array
   */
  public $extra;

  /**
   * The join type, so for example LEFT (default) or INNER.
   *
   * @var string
   */
  public $type;

  /**
   * The configuration array passed by initJoin.
   *
   * @var array
   *
   * @see Drupal\views\Plugin\views\join\JoinPluginBase::initJoin()
   */
  public $configuration = array();

  /**
   * How all the extras will be combined. Either AND or OR.
   *
   * @var string
   */
  public $extraOperator;

  /**
   * Defines whether a join has been adjusted.
   *
   * Views updates the join object to set the table alias instead of the table
   * name. Once views has changed the alias it sets the adjusted value so it
   * does not have to be updated anymore. If you create your own join object
   * you should set the adjusted in the definition array to TRUE if you already
   * know the table alias.
   *
   * @var bool
   *
   * @see Drupal\views\Plugin\HandlerBase::getTableJoin()
   * @see Drupal\views\Plugin\views\query\Sql::adjust_join()
   * @see Drupal\views\Plugin\views\relationship\RelationshipPluginBase::query()
   */
  public $adjusted;

  /**
   * Constructs a Drupal\views\Plugin\views\join\JoinPluginBase object.
   */
  public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
    parent::__construct($configuration, $plugin_id, $discovery);

    // Merge in some default values.
    $configuration += array(
      'type' => 'LEFT',
      'extra_operator' => 'AND',
    );
    $this->configuration = $configuration;
    if (!empty($configuration['table'])) {
      $this->table = $configuration['table'];
    }
    $this->leftTable = $configuration['left_table'];
    $this->leftField = $configuration['left_field'];
    $this->field = $configuration['field'];
    if (!empty($configuration['extra'])) {
      $this->extra = $configuration['extra'];
    }
    if (isset($configuration['adjusted'])) {
      $this->extra = $configuration['adjusted'];
    }
    $this->extraOperator = strtoupper($configuration['extra_operator']);
    $this->type = $configuration['type'];
  }

  /**
   * Build the SQL for the join this object represents.
   *
   * When possible, try to use table alias instead of table names.
   *
   * @param $select_query
   *   An implementation of SelectQueryInterface.
   * @param $table
   *   The base table to join.
   * @param $view_query
   *   The source query, implementation of views_plugin_query.
   */
  public function buildJoin($select_query, $table, $view_query) {
    if (empty($this->configuration['table formula'])) {
      $right_table = $this->table;
    }
    else {
      $right_table = $this->configuration['table formula'];
    }
    if ($this->leftTable) {
      $left = $view_query
        ->get_table_info($this->leftTable);
      $left_field = "{$left['alias']}.{$this->leftField}";
    }
    else {

      // This can be used if left_field is a formula or something. It should be used only *very* rarely.
      $left_field = $this->leftField;
    }
    $condition = "{$left_field} = {$table['alias']}.{$this->field}";
    $arguments = array();

    // 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'])) {

            // If we're aware of a table alias for this table, use the table
            // alias instead of the table name.
            if (isset($left) && $left['table'] == $info['table']) {
              $join_table = $left['alias'] . '.';
            }
            else {
              $join_table = $info['table'] . '.';
            }
          }

          // Convert a single-valued array of values to the single-value case,
          // and transform from IN() notation to = notation
          if (is_array($info['value']) && count($info['value']) == 1) {
            if (empty($info['operator'])) {
              $operator = '=';
            }
            else {
              $operator = $info['operator'] == 'NOT IN' ? '!=' : '=';
            }
            $info['value'] = array_shift($info['value']);
          }
          if (is_array($info['value'])) {

            // With an array of values, we need multiple placeholders and the
            // 'IN' operator is implicit.
            foreach ($info['value'] as $value) {
              $placeholder_i = ':views_join_condition_' . $select_query
                ->nextPlaceholder();
              $arguments[$placeholder_i] = $value;
            }
            $operator = !empty($info['operator']) ? $info['operator'] : 'IN';
            $placeholder = '( ' . implode(', ', array_keys($arguments)) . ' )';
          }
          else {

            // With a single value, the '=' operator is implicit.
            $operator = !empty($info['operator']) ? $info['operator'] : '=';
            $placeholder = ':views_join_condition_' . $select_query
              ->nextPlaceholder();
            $arguments[$placeholder] = $info['value'];
          }
          $extras[] = "{$join_table}{$info['field']} {$operator} {$placeholder}";
        }
        if ($extras) {
          if (count($extras) == 1) {
            $condition .= ' AND ' . array_shift($extras);
          }
          else {
            $condition .= ' AND (' . implode(' ' . $this->extraOperator . ' ', $extras) . ')';
          }
        }
      }
      elseif ($this->extra && is_string($this->extra)) {
        $condition .= " AND ({$this->extra})";
      }
    }
    $select_query
      ->addJoin($this->type, $right_table, $table['alias'], $condition, $arguments);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
JoinPluginBase::$adjusted public property Defines whether a join has been adjusted.
JoinPluginBase::$configuration public property The configuration array passed by initJoin. Overrides PluginBase::$configuration
JoinPluginBase::$extra public property An array of extra conditions on the join.
JoinPluginBase::$extraOperator public property How all the extras will be combined. Either AND or OR.
JoinPluginBase::$field public property The field to join on (right field).
JoinPluginBase::$leftField public property The field we join to.
JoinPluginBase::$leftTable public property The table we join to.
JoinPluginBase::$table public property The table to join (right table).
JoinPluginBase::$type public property The join type, so for example LEFT (default) or INNER.
JoinPluginBase::buildJoin public function Build the SQL for the join this object represents. 2
JoinPluginBase::__construct public function Constructs a Drupal\views\Plugin\views\join\JoinPluginBase object. Overrides PluginBase::__construct 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.