Skip to content

Instantly share code, notes, and snippets.

@nimmneun
Last active October 20, 2016 08:49
Show Gist options
  • Save nimmneun/a2095e05203548ba0756 to your computer and use it in GitHub Desktop.
Save nimmneun/a2095e05203548ba0756 to your computer and use it in GitHub Desktop.
Simple MySQL query builder
<?php namespace MonoQuery;
/**
* Uber simple single table query builder.
*
* @author neun
* @since 27.09.2015 15:35
*/
class Query
{
private $table;
private $type;
private $limit;
private $order;
private $sql;
private $wheres = [];
private $values = [];
private $columns = [];
private $inserts = [];
private $joins = [];
private $stms = [
'select' => "SELECT\n %3\$s\nFROM\n `%1\$s`\nWHERE %2\$s\n%5\$s\n%6\$s",
'insert' => "INSERT INTO\n `%1\$s`\n (%3\$s)\nVALUES\n (%4\$s)",
'update' => "UPDATE\n `%1\$s`\nSET %3\$s\nWHERE %2\$s",
'delete' => "DELETE FROM\n `%1\$s`\nWHERE %2\$s",
];
private function __construct($table, $type)
{
$this->table = $table;
$this->type = $type;
}
/**
* Query::from('user')->select(['id', 'email'])->where('id')->equals('1')
*
* @param string $table
* @return Query
*/
public static function from($table)
{
return new Query($table, 'select');
}
/**
* Query::insert('user')->values([])
*
* @param string $table
* @return Query
*/
public static function insert($table)
{
return new Query($table, 'insert');
}
/**
* Query::update('user')->set([])->where('id')->equals('1')
*
* @param string $table
* @return Query
*/
public static function update($table)
{
return new Query($table, 'update');
}
/**
* Query::delete('user')->where('id')->equals(6)
*
* @param string $table
* @return Query
*/
public static function delete($table)
{
return new Query($table, 'delete');
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @param array $args
* @return Query
*/
public function innerJoin($args)
{
$join = "INNER JOIN\n ";
$this->buildJoins($args, $join);
return $this;
}
/**
* @param array $args
* @return Query
*/
public function leftJoin($args)
{
$join = "LEFT JOIN\n ";
$this->buildJoins($args, $join);
return $this;
}
/**
* @param array $columns
* @return Query
*/
public function select(array $columns)
{
foreach ($columns as $column) {
list($table, $field) = self::split($column);
$table = null !== $table ? self::escape($table).'.' : null;
$field = $field != '*' ? self::escape($field) : '*';
$this->columns[] = $table.$field;
}
return $this;
}
/**
* @param string $column
* @param string $andOr
* @return Query
*/
public function where($column, $andOr = 'AND')
{
$table = null;
if (false !== strpos($column, '.')) {
list ($table, $column) = explode('.', $column);
$table = self::escape($table).'.';
}
$this->wheres[] = 0 !== count($this->values)
? "\n ".$andOr." ".$table.self::escape($column)
: "\n ".$table.self::escape($column);
return $this;
}
/**
* @param array $values
* @return Query
*/
public function values(array $values)
{
foreach ($values as $column => $value) {
$this->columns[] = self::escape($column);
$this->inserts[] = self::quote($value);
}
return $this;
}
/**
* @param array $values
* @return Query
*/
public function set(array $values)
{
foreach ($values as $column => $value) {
$this->columns[] = "\n ".self::escape($column).' = '.self::quote($value);
}
return $this;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @param string $value
* @return Query
*/
public function equals($value)
{
$this->values[] = array_pop($this->wheres).' = '.self::quote($value);
return $this;
}
/**
* @param string $value
* @return Query
*/
public function greater($value)
{
$this->values[] = array_pop($this->wheres).' > '.self::quote($value);
return $this;
}
/**
* @param string $value
* @return Query
*/
public function lesser($value)
{
$this->values[] = array_pop($this->wheres).' < '.self::quote($value);
return $this;
}
/**
* @param string $value
* @return Query
*/
public function like($value)
{
$this->values[] = array_pop($this->wheres).' LIKE '.self::quote($value);
return $this;
}
/**
* @param string $value1
* @param string $value2
* @return Query
*/
public function between($value1, $value2)
{
$this->values[] = array_pop($this->wheres).' BETWEEN '
.self::quote($value1).' AND '
.self::quote($value2);
return $this;
}
/**
* @param string $value1
* @param string $value2
* @return Query
*/
public function notBetween($value1, $value2)
{
$this->values[] = array_pop($this->wheres).' NOT BETWEEN '
.self::quote($value1).' AND '
.self::quote($value2);
return $this;
}
/**
* @param string $limit
* @return Query
*/
public function limit($limit = null)
{
$this->limit = null === $limit ? '' : 'LIMIT '.$limit;
return $this;
}
/**
* @param string $order
* @param string $dir
* @return Query
*/
public function orderBy($order = null, $dir = 'ASC')
{
$this->order = null === $order ? '' : 'ORDER BY '.self::escape($order).' '.$dir;
return $this;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @return string
*/
public function build()
{
if (0 !== count($this->joins)) {
$joins = '';
foreach ($this->joins as $join) {
$joins .= $join;
}
$this->stms[$this->type] = str_replace('WHERE', $joins.'WHERE', $this->stms[$this->type]);
}
$this->sql = preg_replace(
"/\n+/", "\n",
sprintf($this->stms[$this->type],
$this->table,
implode(' ', $this->values),
implode(', ', $this->columns),
implode(', ', $this->inserts),
$this->order,
$this->limit
)
);
return $this->sql;
}
/**
* @param \PDO $pdo
* @return \PDOStatement
*/
public function run(\PDO $pdo)
{
if (0 === strlen($this->sql)) {
$this->build();
}
return $pdo->query($this->sql);
}
/**
* Nasty quick and dirty solution *lol
*
* @param array $args
* @param string $join
*/
private function buildJoins($args, $join)
{
$table = null;
foreach ($args as $field1 => $field2) {
list($table1, $column1) = self::split($field1);
list($table2, $column2) = self::split($field2);
if (!isset($table)) {
$table = $table2;
}
if (false === strpos($join, ' ON ')) {
$join .= self::escape($table2).' ON ';
} else {
$join .= ' AND ';
}
$join .= self::escape($table1).'.'.self::escape($column1);
if (null === $table2) {
$join .= ' = '.self::quote($column2);
} else {
$join .= ' = '.self::escape($table2).'.'.self::escape($column2);
}
}
$this->joins[$table] = $join."\n";
}
/**
* @param string $string
* @return string
*/
private static function escape($string)
{
return '`'.$string.'`';
}
/**
* @param string $string
* @return string
*/
private static function quote($string)
{
return '\''.str_replace(['\''], ['\\\''], $string).'\'';
}
/**
* @param string $value
* @return array
*/
private static function split($value)
{
return 2 === count($tmp = explode('.', $value)) ? $tmp : [null, $value];
}
}
@nimmneun
Copy link
Author

    echo MonoQuery\Query::from('customer')
        ->select(['first_name', 'last_name', 'order.ext_id', 'order.total', 'product.*'])
        ->innerJoin(['customer.id' => 'order.customer_id'])
        ->innerJoin(['order.id' => 'order_item.order_id'])
        ->innerJoin(['order_item.product_id' => 'product.id'])
        ->where('product.id')->between(3,7)->limit(5)
        ->build();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment