class JoinPluginBase

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 drupal/core/modules/views/lib/Drupal/views/Tests/Plugin/JoinTest.php
Definition of Drupal\views\Tests\Plugin\JoinTest.
JoinTest.php in drupal/core/modules/views/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 drupal/core/modules/views/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 drupal/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php
Definition of Drupal\views\Plugin\views\query\Sql.

File

drupal/core/modules/views/lib/Drupal/views/Plugin/views/join/JoinPluginBase.php, line 52
Definition of Drupal\views\Plugin\views\join\JoinPluginBase.

Namespace

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

  /**
   * 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, array $plugin_definition) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);

    // 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->adjusted = $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
        ->getTableInfo($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
ContainerFactoryPluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 11
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.
PluginBase::$pluginId protected property The plugin_id.
PluginBase::getPluginDefinition public function Returns the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition
PluginBase::getPluginId public function Returns the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId