protected function _buildSql()
{
if (count($this->_union) !== 0) {
return $this->_getUnionSql();
}
if (count($this->_models) === 0) {
throw new QueryBuilderException('at least one model is required to build the query');
}
$sql = 'SELECT ';
if ($this->_distinct) {
$sql .= 'DISTINCT ';
}
if ($this->_columns !== null) {
$columns = $this->_columns;
} else {
$columns = '';
$selectedColumns = [];
/** @noinspection ForeachSourceInspection */
foreach ($this->_models as $alias => $model) {
$selectedColumns[] = '[' . (is_int($alias) ? $model : $alias) . '].*';
}
$columns .= implode(', ', $selectedColumns);
}
$sql .= $columns;
$selectedModels = [];
/** @noinspection ForeachSourceInspection */
foreach ($this->_models as $alias => $model) {
if ($model instanceof $this) {
if (is_int($alias)) {
throw new QueryBuilderException('if using SubQuery, you must assign an alias for it');
}
$selectedModels[] = '(' . $model->getSql() . ') AS [' . $alias . ']';
/** @noinspection SlowArrayOperationsInLoopInspection */
$this->_bind = array_merge($this->_bind, $model->getBind());
} else {
if (is_string($alias)) {
$selectedModels[] = '[' . $model . '] AS [' . $alias . ']';
} else {
$selectedModels[] = '[' . $model . ']';
}
}
}
$sql .= ' FROM ' . implode(', ', $selectedModels);
$joinSQL = '';
/** @noinspection ForeachSourceInspection */
foreach ($this->_joins as $join) {
$joinModel = $join[0];
/** @noinspection MultiAssignmentUsageInspection */
$joinCondition = $join[1];
/** @noinspection MultiAssignmentUsageInspection */
$joinAlias = $join[2];
/** @noinspection MultiAssignmentUsageInspection */
$joinType = $join[3];
if ($joinAlias !== null) {
$this->_models[$joinAlias] = $joinModel;
} else {
$this->_models[] = $joinModel;
}
if ($joinType !== null) {
$joinSQL .= ' ' . $joinType;
}
if ($joinModel instanceof $this) {
$joinSQL .= ' JOIN (' . $joinModel->getSql() . ')';
/** @noinspection SlowArrayOperationsInLoopInspection */
$this->_bind = array_merge($this->_bind, $joinModel->getBind());
if ($joinAlias === null) {
throw new QueryBuilderException('if using SubQuery, you must assign an alias for it');
}
} else {
$joinSQL .= ' JOIN [' . $joinModel . ']';
}
if ($joinAlias !== null) {
$joinSQL .= ' AS [' . $joinAlias . ']';
}
if ($joinCondition) {
$joinSQL .= ' ON ' . $joinCondition;
}
}
$sql .= $joinSQL;
$wheres = [];
if (is_string($this->_conditions)) {
$this->_conditions = [$this->_conditions];
}
/** @noinspection ForeachSourceInspection */
foreach ($this->_conditions as $k => $v) {
if ($v === '') {
continue;
}
if (is_int($k)) {
$wheres[] = Text::contains($v, ' or ', true) ? "({$v})" : $v;
} else {
$wheres[] = "[{$k}]=:{$k}";
$this->_bind[$k] = $v;
}
}
if (count($wheres) !== 0) {
$sql .= ' WHERE ' . implode(' AND ', $wheres);
}
if ($this->_group !== null) {
$sql .= ' GROUP BY ' . $this->_group;
}
if ($this->_having !== null) {
$sql .= ' HAVING ' . $this->_having;
}
if ($this->_order !== null) {
$sql .= ' ORDER BY ' . $this->_order;
}
if ($this->_limit !== 0) {
$sql .= ' LIMIT ' . $this->_limit;
}
if ($this->_offset !== 0) {
$sql .= ' OFFSET ' . $this->_offset;
}
if ($this->_forUpdate) {
$sql .= ' FOR UPDATE';
}
//compatible with other SQL syntax
$replaces = [];
foreach ($this->_bind as $key => $_) {
$replaces[':' . $key . ':'] = ':' . $key;
}
$sql = strtr($sql, $replaces);
/** @noinspection ForeachSourceInspection */
foreach ($this->_models as $model) {
if (!$model instanceof $this) {
$sql = str_replace('[' . $model . ']', '[' . $this->modelsManager->getModelSource($model) . ']', $sql);
}
}
return $sql;
}