A super easy PHP Framework for web development! https://github.com/exacti/phacil-framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
9.6 KiB

<?php
/**
* Copyright © 2023 ExacTI Technology Solutions. All rights reserved.
* GPLv3 General License.
* https://exacti.com.br
* Phacil PHP Framework - https://github.com/exacti/phacil-framework
*/
namespace Phacil\Framework\MagiQL;
use Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory;
use Phacil\Framework\MagiQL\Manipulation\AbstractBaseQuery;
use Phacil\Framework\MagiQL\Api\QueryInterface;
use Phacil\Framework\MagiQL\Manipulation\QueryFactory;
use Phacil\Framework\MagiQL\Manipulation\Select;
use Phacil\Framework\MagiQL\Syntax\Column;
use Phacil\Framework\MagiQL\Syntax\Table;
/**
* Class Generic.
*/
class Builder implements \Phacil\Framework\MagiQL\Api\BuilderInterface
{
/**
* The placeholder parameter bag.
*
* @var \Phacil\Framework\MagiQL\Builder\Syntax\PlaceholderWriter
*/
protected $placeholderWriter;
/**
* The Where writer.
*
* @var \Phacil\Framework\MagiQL\Builder\Syntax\WhereWriter
*/
protected $whereWriter;
/**
* The SQL formatter.
*
* @var \NilPortugues\Sql\QueryFormatter\Formatter
*/
protected $sqlFormatter;
/**
* Class namespace for the query pretty output formatter.
* Required to create the instance only if required.
*
* @var string
*/
protected $sqlFormatterClass = 'NilPortugues\Sql\QueryFormatter\Formatter';
/**
* Array holding the writers for each query part. Methods are called upon request and stored in
* the $queryWriterInstances array.
*
* @var array
*/
protected $queryWriterArray = [
'SELECT' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createSelectWriter',
'INSERT' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createInsertWriter',
'UPDATE' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createUpdateWriter',
'DELETE' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createDeleteWriter',
'INTERSECT' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createIntersectWriter',
'MINUS' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createMinusWriter',
'UNION' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createUnionWriter',
'UNION ALL' => '\Phacil\Framework\MagiQL\Builder\Syntax\WriterFactory::createUnionAllWriter',
];
/**
* Array that stores instances of query writers.
*
* @var array
*/
protected $queryWriterInstances = [
'SELECT' => null,
'INSERT' => null,
'UPDATE' => null,
'DELETE' => null,
'INTERSECT' => null,
'MINUS' => null,
'UNION' => null,
'UNION ALL' => null,
];
/**
* Creates writers.
*/
public function __construct()
{
$this->placeholderWriter = WriterFactory::createPlaceholderWriter();
}
/**
* @param string $table
* @param array $columns
*
* @return \Phacil\Framework\MagiQL\Manipulation\Select
*/
public function select($table = null, array $columns = null)
{
return $this->injectBuilder(QueryFactory::createSelect($table, $columns));
}
/**
* @param \Phacil\Framework\MagiQL\Manipulation\AbstractBaseQuery
*
* @return \Phacil\Framework\MagiQL\Manipulation\AbstractBaseQuery
*/
protected function injectBuilder(AbstractBaseQuery $query)
{
return $query->setBuilder($this);
}
/**
* @param string $table
* @param array $values
*
*@return AbstractBaseQuery
*/
public function insert($table = null, array $values = null)
{
return $this->injectBuilder(QueryFactory::createInsert($table, $values));
}
/**
* @param string $table
* @param array $values
*
*@return AbstractBaseQuery
*/
public function update($table = null, array $values = null)
{
return $this->injectBuilder(QueryFactory::createUpdate($table, $values));
}
/**
* @param string $table
*
* @return \Phacil\Framework\MagiQL\Manipulation\Delete
*/
public function delete($table = null)
{
return $this->injectBuilder(QueryFactory::createDelete($table));
}
/**
* @return \Phacil\Framework\MagiQL\Manipulation\Intersect
*/
public function intersect()
{
return QueryFactory::createIntersect();
}
/**
* @return \Phacil\Framework\MagiQL\Manipulation\Union
*/
public function union()
{
return QueryFactory::createUnion();
}
/**
* @return \Phacil\Framework\MagiQL\Manipulation\UnionAll
*/
public function unionAll()
{
return QueryFactory::createUnionAll();
}
/**
* @param \Phacil\Framework\MagiQL\Manipulation\Select $first
* @param \Phacil\Framework\MagiQL\Manipulation\Select $second
*
* @return \Phacil\Framework\MagiQL\Manipulation\Minus
*/
public function minus(Select $first, Select $second)
{
return QueryFactory::createMinus($first, $second);
}
/**
* @return array
*/
public function getValues()
{
return $this->placeholderWriter->get();
}
/**
* Returns a SQL string in a readable human-friendly format.
*
* @param QueryInterface $query
*
* @return string
*/
public function writeFormatted(QueryInterface $query)
{
if (null === $this->sqlFormatter) {
$this->sqlFormatter = (new \ReflectionClass($this->sqlFormatterClass))->newInstance();
}
return $this->sqlFormatter->format($this->write($query));
}
/**
* @param QueryInterface $query
* @param bool $resetPlaceholders
*
* @return string
*
* @throws \RuntimeException
*/
public function write(QueryInterface $query, $resetPlaceholders = true)
{
if ($resetPlaceholders) {
$this->placeholderWriter->reset();
}
$queryPart = $query->partName();
if (false === empty($this->queryWriterArray[$queryPart])) {
$this->createQueryObject($queryPart);
return $this->queryWriterInstances[$queryPart]->write($query);
}
throw new \RuntimeException('Query builder part not defined.');
}
/**
* @param Select $select
*
* @return string
*/
public function writeJoin(Select $select)
{
if (null === $this->whereWriter) {
$this->whereWriter = WriterFactory::createWhereWriter($this, $this->placeholderWriter);
}
$sql = ($select->getJoinType()) ? "{$select->getJoinType()} " : '';
$sql .= 'JOIN ';
$sql .= $this->writeTableWithAlias($select->getTable());
$sql .= ' ON ';
$sql .= $this->whereWriter->writeWhere($select->getJoinCondition());
return $sql;
}
/**
* @param Table $table
*
* @return string
*/
public function writeTableWithAlias(Table $table)
{
$alias = ($table->getAlias()) ? " AS {$this->writeTableAlias($table->getAlias())}" : '';
$schema = ($table->getSchema()) ? "{$table->getSchema()}." : '';
return $schema.$this->writeTableName($table).$alias;
}
/**
* @param $alias
*
* @return mixed
*/
public function writeTableAlias($alias)
{
return $alias;
}
/**
* Returns the table name.
*
* @param Table $table
*
* @return string
*/
public function writeTableName(Table $table)
{
return $table->getName();
}
/**
* @param string $alias
*
* @return string
*/
public function writeColumnAlias($alias)
{
return sprintf('"%s"', $alias);
}
/**
* @param Table $table
*
* @return string
*/
public function writeTable(Table $table)
{
$schema = ($table->getSchema()) ? "{$table->getSchema()}." : '';
return $schema.$this->writeTableName($table);
}
/**
* @param array $values
*
* @return array
*/
public function writeValues(array &$values)
{
\array_walk(
$values,
function (&$value) {
$value = $this->writePlaceholderValue($value);
}
);
return $values;
}
/**
* @param $value
*
* @return string
*/
public function writePlaceholderValue($value)
{
return $this->placeholderWriter->add($value);
}
/**
* @param $operator
*
* @return string
*/
public function writeConjunction($operator)
{
return ' '.$operator.' ';
}
/**
* @return string
*/
public function writeIsNull()
{
return ' IS NULL';
}
/**
* @return string
*/
public function writeIsNotNull()
{
return ' IS NOT NULL';
}
/**
* Returns the column name.
*
* @param Column $column
*
* @return string
*/
public function writeColumnName(Column $column)
{
$name = $column->getName();
if ($name === Column::ALL) {
return $this->writeColumnAll();
}
return $name;
}
/**
* @return string
*/
protected function writeColumnAll()
{
return '*';
}
/**
* @param string $queryPart
*/
protected function createQueryObject($queryPart)
{
if (null === $this->queryWriterInstances[$queryPart]) {
$this->queryWriterInstances[$queryPart] = \call_user_func_array(
\explode('::', $this->queryWriterArray[$queryPart]),
[$this, $this->placeholderWriter]
);
}
}
}