gplx/mediawiki/includes/libs/rdbms/querybuilder/JoinGroupBase.php

153 lines
5.2 KiB
PHP

<?php
namespace Wikimedia\Rdbms;
use InvalidArgumentException;
/**
* Shared code between SelectQueryBuilder and JoinGroup to represent tables and join conditions.
*
* @internal
*/
abstract class JoinGroupBase {
/** @var array */
protected $tables = [];
/** @var array */
protected $joinConds = [];
/** @var string|null */
protected $lastAlias;
/**
* Add a single table or a single parenthesized group.
*
* @param string|JoinGroup|SelectQueryBuilder $table The unqualified name of a table,
* a table name of the form "information_schema.<unquoted identifier>", a JoinGroup
* containing multiple tables, or a SelectQueryBuilder representing a subquery.
* @param-taint $table exec_sql
* @param string|null $alias The table alias, or null for no alias
* @param-taint $alias exec_sql
* @return $this
*/
public function table( $table, $alias = null ) {
if ( $table instanceof JoinGroup ) {
$alias ??= $table->getAlias();
$table = $table->getRawTables();
} elseif ( $table instanceof SelectQueryBuilder ) {
$alias ??= $this->getAutoAlias();
$table = new Subquery( $table->getSQL() );
} elseif ( $table instanceof Subquery ) {
if ( $alias === null ) {
throw new InvalidArgumentException( __METHOD__ .
': Subquery as table must provide an alias.' );
}
} elseif ( !is_string( $table ) ) {
throw new InvalidArgumentException( __METHOD__ .
': $table must be either string, JoinGroup or SelectQueryBuilder' );
}
if ( $alias === null ) {
$this->tables[] = $table;
$this->lastAlias = $table;
} else {
$this->tables[$alias] = $table;
$this->lastAlias = $alias;
}
return $this;
}
/**
* Left join a table or group of tables. This should be called after table().
*
* @param string|JoinGroup|SelectQueryBuilder $table The unqualified name of a table,
* a table name of the form "information_schema.<unquoted identifier>", a JoinGroup
* containing multiple tables, or a SelectQueryBuilder representing a subquery.
* @param string|null $alias The alias name, or null to automatically
* generate an alias which will be unique to this builder
* @param string|array $conds The conditions for the ON clause
* @return $this
*/
public function leftJoin( $table, $alias = null, $conds = [] ) {
$this->addJoin( 'LEFT JOIN', $table, $alias, $conds );
return $this;
}
/**
* Inner join a table or group of tables. This should be called after table().
*
* @param string|JoinGroup|SelectQueryBuilder $table The unqualified name of a table,
* a table name of the form "information_schema.<unquoted identifier>", a JoinGroup
* containing multiple tables, or a SelectQueryBuilder representing a subquery.
* @param string|null $alias The alias name, or null to automatically
* generate an alias which will be unique to this builder
* @param string|array $conds The conditions for the ON clause
* @return $this
*/
public function join( $table, $alias = null, $conds = [] ) {
$this->addJoin( 'JOIN', $table, $alias, $conds );
return $this;
}
/**
* Straight join a table or group of tables. This should be called after table().
*
* @param string|JoinGroup|SelectQueryBuilder $table The unqualified name of a table,
* a table name of the form "information_schema.<unquoted identifier>", a JoinGroup
* containing multiple tables, or a SelectQueryBuilder representing a subquery.
* @param string|null $alias The alias name, or null to automatically
* generate an alias which will be unique to this builder
* @param string|array $conds The conditions for the ON clause
* @return $this
*/
public function straightJoin( $table, $alias = null, $conds = [] ) {
$this->addJoin( 'STRAIGHT_JOIN', $table, $alias, $conds );
return $this;
}
/**
* Private helper for functions that add joins
* @param string $type
* @param string|JoinGroup|SelectQueryBuilder $table
* @param string|null $alias
* @param string|array $joinConds
*/
private function addJoin( $type, $table, $alias, $joinConds ) {
if ( !$this->tables ) {
throw new \LogicException( __METHOD__ .
': cannot add a join unless a regular table is added first' );
}
if ( $alias === null ) {
if ( is_string( $table ) ) {
$alias = $table;
} else {
$alias = $this->getAutoAlias();
}
}
if ( isset( $this->joinConds[$alias] ) ) {
throw new \LogicException( __METHOD__ .
": a join with alias \"$alias\" has already been added" );
}
if ( $table instanceof JoinGroup ) {
$conflicts = array_intersect_key( $this->joinConds, $table->getRawJoinConds() );
if ( $conflicts ) {
$conflict = reset( $conflicts );
throw new \LogicException( __METHOD__ .
": a join with alias \"$conflict\" has already been added" );
}
$this->tables[$alias] = $table->getRawTables();
$this->joinConds += $table->getRawJoinConds();
} elseif ( $table instanceof SelectQueryBuilder ) {
$this->tables[$alias] = new Subquery( $table->getSQL() );
} elseif ( is_string( $table ) ) {
$this->tables[$alias] = $table;
} else {
throw new InvalidArgumentException( __METHOD__ .
': $table must be either string, JoinGroup or SelectQueryBuilder' );
}
$this->joinConds[$alias] = [ $type, $joinConds ];
$this->lastAlias = $alias;
}
abstract protected function getAutoAlias();
}