| Current Path : /var/www/html/administrator/components/com_komento/includes/sql/ |
| Current File : /var/www/html/administrator/components/com_komento/includes/sql/sql.php |
<?php
/**
* @package Komento
* @copyright Copyright (C) Stack Ideas Sdn Bhd. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Komento is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/
defined('_JEXEC') or die('Unauthorized Access');
class KomentoSql
{
static $instance = null;
public $db = null;
public $jConfig = null;
public $debug = false;
/**
* Stores the data internally in index format.
* @var array
*/
private $data = array();
/**
* Stores the a unparsed Sql
* @var string
*/
private $string = '';
/**
* Set the mode of the sql
* @var string
*/
private $mode = 'select';
/**
* Set the last action of the sql
* @var string
*/
private $action = 'where';
public static function factory()
{
return new self();
}
public function __construct()
{
$this->jConfig = FH::jConfig();
$this->db = KT::db();
}
public function __call( $method, $args )
{
if( !is_callable( array( $this->db, $method ) ) )
{
return false;
}
$query = '';
if( isset($args[0]) )
{
$query = $args[0];
}
else
{
$query = $this->getSql();
}
$this->db->setQuery( $query );
return $this->db->$method();
}
/**
* START OF USER BUILD FUNCTIONS
*/
public function clear()
{
// Reset all the data
$this->data = array();
$this->mode = 'select';
$this->action = 'where';
$this->string = '';
}
public function delete( $table )
{
// Set the mode
$this->mode = 'delete';
$this->data['table'] = array( $table, '' );
return $this;
}
public function select( $table, $alias = '' )
{
// Set the mode
$this->mode = 'select';
$this->data['table'] = array( $table, $alias );
return $this;
}
public function column( $column, $alias = '', $function = '', $psuedo = false )
{
if( !isset( $this->data['columns'] ) )
{
$this->data['columns'] = array();
}
$this->data['columns'][] = array( $column, $alias, $function, $psuedo );
return $this;
}
public function update( $table, $alias = '' )
{
$this->mode = 'update';
$this->data['table'] = array( $table, $alias );
return $this;
}
public function set( $column, $value, $isValue = true )
{
if( !isset( $this->data['set'] ) )
{
$this->data['set'] = array();
}
$this->data['set'][] = array( $column, $value, $isValue );
return $this;
}
public function insert( $table, $columns = array() )
{
$this->mode = 'insert';
$this->data['table'] = array( $table, '' );
return $this;
}
public function values()
{
if( !isset( $this->data['values'] ) )
{
$this->data['values'] = array();
}
$this->data['values'][] = func_get_args();
return $this;
}
public function join( $table, $alias, $type = 'LEFT' )
{
if( !isset( $this->data['join'] ) )
{
$this->data['join'] = array();
}
$this->data['join'][] = array( $table, $alias, $type );
return $this;
}
public function leftjoin( $tableName, $alias = '' )
{
return $this->join( $tableName, $alias, 'LEFT' );
}
public function rightjoin( $tableName, $alias = '' )
{
return $this->join( $tableName, $alias, 'RIGHT' );
}
public function innerjoin( $tableName, $alias = '' )
{
return $this->join( $tableName, $alias, 'INNER' );
}
public function on( $columnA, $columnB = '', $type = '=', $condition = 'AND' )
{
// Mark the last action
$this->action = 'on';
if( !isset( $this->data['on'] ) )
{
$this->data['on'] = array();
}
$joinindex = count( $this->data['join'] ) - 1;
if( !isset( $this->data['on'][$joinindex] ) )
{
$this->data['on'][$joinindex] = array();
}
$this->data['on'][$joinindex][] = array( $columnA, $columnB, $type, $condition );
return $this;
}
public function where( $column, $value = '', $type = '=', $condition = 'AND' )
{
// Mark the last action
$this->action = 'where';
if( !isset( $this->data['where'] ) )
{
$this->data['where'] = array();
}
$this->data['where'][] = array( $column, $value, $type, $condition );
return $this;
}
public function isnull( $column )
{
// Mark the last action
$this->action = 'where';
if( !isset( $this->data['where'] ) )
{
$this->data['where'] = array();
}
$this->data['where'][] = array( $column, NULL, 'IS', 'AND' );
return $this;
}
public function exists( $query )
{
// Mark the last action
$this->action = 'exists';
if( !isset( $this->data['exists'] ) )
{
$this->data['exists'] = array();
}
$this->data['exists'][] = $query;
return $this;
}
public function group()
{
if( !isset( $this->data['group'] ) )
{
$this->data['group'] = array();
}
$columns = func_get_args();
foreach( $columns as $column )
{
$this->data['group'][] = $column;
}
return $this;
}
public function having( $column, $value = '', $type = '=', $condition = 'AND' )
{
// Mark the last action
$this->action = 'having';
if( !isset( $this->data['having'] ) )
{
$this->data['having'] = array();
}
$this->data['having'][] = array( $column, $value, $type, $condition );
return $this;
}
public function order( $column, $direction = 'ASC', $function = '' )
{
if( !isset( $this->data['order'] ) )
{
$this->data['order'] = array();
}
$this->data['order'][] = array( $column, $direction, $function );
return $this;
}
public function limit( $start, $limit = null )
{
// If $limit is null, means that callee is passing in $start as the limit
if( is_null( $limit ) )
{
$limit = $start;
$start = 0;
}
$this->data['limit'] = array( $start, $limit );
return $this;
}
public function raw( $string )
{
$this->string = $string;
return $this;
}
/**
* END OF USER BUILD FUNCTIONS
*/
/**
* START OF STRING RETURN FUNCTIONS
*/
/**
* Throws the sql string back to the browser
*
* @since 1.4
* @access public
* @param string
* @return
*/
public function debug()
{
$this->debug = true;
$prefix = $this->jConfig->getValue('dbprefix');
$query = $this->buildSql();
return str_ireplace( '#__' , $prefix , $query );
}
public function getSql()
{
$query = $this->buildSql();
return $query;
}
public function getTotalSql()
{
// Check for raw string
if( !empty( $this->string ) )
{
$string = $this->parse( $this->string );
$pattern = '/select.+from/i';
$string = preg_replace( $pattern, 'SELECT COUNT(1) FROM', $string );
return $string;
}
$query = $this->buildTotal();
$directives = array( 'join', 'where', 'exists', 'group', 'having' );
$query .= $this->buildDirectives( $directives );
return $query;
}
public function getConditionSql()
{
$query = $this->buildWhere();
// Strip off ' WHERE '
$query = str_replace( ' WHERE ', '', $query );
return $query;
}
public function toString()
{
return $this->__toString();
}
public function __toString()
{
$query = $this->buildSql();
return $query;
}
/**
* END OF STRING RETURN FUNCTIONS
*/
/**
* START OF PARSING FUNCTIONS
*/
public function nameQuote( $string )
{
return $this->db->nameQuote( $string );
}
public function quote( $string )
{
return $this->db->quote( $string );
}
public function parse( $string )
{
return $this->parseNameQuote( $this->parseQuote( $string ) );
}
private function parseNameQuote( $string )
{
$pattern = '/`(.*?)`/i';
$string = preg_replace( $pattern, $this->nameQuote( '$1' ), $string );
return $string;
}
private function parseQuote( $string )
{
$pattern = '/\'(.*?)\'/i';
$string = preg_replace( $pattern, $this->quote( '$1' ), $string );
return $string;
}
private function parseTableName( $string )
{
if( substr( $string, 0, 3 ) !== '#__' )
{
$string = '#__' . $string;
}
return $string;
}
private function parseColumnName( $string )
{
$line = '';
if( $this->hasColumnFunction( $string ) )
{
$line = $this->parse( $string );
}
else
{
$tmp = explode( '.', $string );
foreach( $tmp as &$t )
{
if( $t !== '*' )
{
$t = $this->nameQuote( $t );
}
}
$line = implode( '.', $tmp );
}
return $line;
}
private function hasColumnFunction( $string )
{
static $functions = array( 'count', 'distinct', 'unique', 'sum', 'lower', 'upper' );
foreach( $functions as $function )
{
if( stripos( $string, $function ) === 0 )
{
return true;
}
}
return false;
}
private function parseFunction( $function, $column )
{
// There could be multiple functions
$funcs = array_reverse( explode( ' ', $function ) );
$line = $column;
foreach( $funcs as $func )
{
$line = strtoupper( $func ) . '(' . $line . ')';
}
return $line;
}
/**
* END OF PARSING FUNCTIONS
*/
/**
* START OF INTERNAL BUILDING FUNCTIONS
*/
private function buildSql()
{
// Check for raw string
if (!empty($this->string)) {
$string = $this->parse($this->string);
return $string;
}
// Build base sql from the mode
$method = 'build' . ucfirst($this->mode);
$query = $this->$method();
/* directives
join
where
group
having
order
limit
*/
// Build the remaining pieces of the sql
$directives = array(
'select' => array( 'join', 'where', 'exists', 'group', 'having', 'order', 'limit' ),
'delete' => array( 'where', 'limit' ),
'update' => array( 'join', 'set', 'where', 'limit' ),
'insert' => array( 'values' )
);
$query .= $this->buildDirectives($directives[$this->mode]);
return $query;
}
private function buildDirectives($directives)
{
$query = '';
foreach ($directives as $directive) {
$command = 'build' . ucfirst( $directive );
$query .= $this->$command();
}
return $query;
}
private function buildDelete()
{
$table = $this->data['table'];
$query = 'DELETE FROM ' . $this->nameQuote( $table[0] );
return $query;
}
private function buildSelect($debug = false)
{
$columns = array();
// If no columns, then set the default column as *
if (!isset($this->data['columns'])) {
$this->data['columns'] = array(array('*', '', '', false));
}
foreach ($this->data['columns'] as $column) {
list($columnName, $alias, $function, $psuedo) = $column;
$name = $this->parseColumnName($column[0]);
if ($psuedo) {
$columnName = $this->quote($columnName);
} else {
$columnName = $this->parseColumnName($column[0]);
}
// Set line as the column name
$line = $columnName;
if (!empty($function)) {
$line = $this->parseFunction($function, $line);
}
if (!empty($alias)) {
$line .= ' AS ' . $this->nameQuote($alias);
}
$columns[] = $line;
}
// Build the columns string
$columns = implode( ',', $columns );
// Main select query string
$query = 'SELECT ' . $columns . ' FROM ' . $this->nameQuote($this->data['table'][0]);
// Set table alias
if (!empty($this->data['table'][1])) {
$query .= ' AS ' . $this->nameQuote($this->data['table'][1]);
}
return $query;
}
private function buildUpdate()
{
$query = 'UPDATE ' . $this->data['table'][0];
// Set table alias
if( !empty( $this->data['table'][1] ) )
{
$query .= ' AS ' . $this->nameQuote( $this->data['table'][1] );
}
return $query;
}
private function buildSet()
{
$query = array();
$set = $this->data['set'];
$iLength = count( $set );
for( $i = 0; $i < $iLength; $i++ )
{
list( $column, $value, $isValue ) = $set[$i];
// The value could be just not a value
if( !$isValue || stripos( $value, '`' ) !== false )
{
$value = $this->parse( $value );
}
else
{
$value = $this->quote( $value );
}
$query[] = $this->parseColumnName( $column ) . ' = ' . $value;
}
$query = count( $query ) > 0 ? ' SET ' . implode( ', ', $query ) : '';
return $query;
}
private function buildInsert()
{
$query[] = 'INSERT INTO ' . $this->data[ 'table' ][ 0 ];
$values = array();
if( !empty( $this->data[ 'values' ] ) )
{
foreach( $this->data[ 'values' ] as $index => $pair )
{
list( $column , $value ) = $pair;
// The value could be just not a value
if( stripos( $value, '`' ) !== false )
{
$value = $this->parse( $value );
}
else
{
$value = $this->quote( $value );
}
$columns[] = $this->parseColumnName( $column );
$values[] = $value;
}
}
$query[] = '(';
$query[] = implode( ',' , $columns );
$query[] = ')';
$query[] = 'VALUES(';
$query[] = implode( ',' , $values );
$query[] = ')';
$query = implode( ' ' , $query );
return $query;
}
private function buildValues()
{
}
private function buildTotal()
{
// Main total query string
$query = 'SELECT COUNT(1) FROM ' . $this->nameQuote( $this->data['table'][0] );
// Set table alias
if( !empty( $this->data['table'][1] ) )
{
$query .= ' AS ' . $this->nameQuote( $this->data['table'][1] );
}
return $query;
}
private function buildWhere()
{
// $this->data['where'][] = array( $column, $value, $type, $condition );
if( !isset( $this->data['where'] ) )
{
return '';
}
$where = $this->data['where'];
$query = array();
$joiner = false;
$length = count( $where );
for( $i = 0; $i < $length; $i++ )
{
list( $column, $value, $type, $condition ) = $where[$i];
$line = '';
// For second condition and above, we need the condition joiner
if( $joiner )
{
$line = strtoupper( $condition ) . ' ';
}
else
{
$joiner = true;
}
if( $column === '(' || ( isset( $where[$i + 1 ] ) && $where[$i + 1][0] === ')' ) )
{
$joiner = false;
}
if( $column === '(' || $column === ')' )
{
$line .= $column;
}
else
{
$line .= $this->buildCondition( $column, $value, $type );
}
$query[] = $line;
}
$query = count( $query ) > 0 ? ' WHERE ' . implode( ' ', $query ) : '';
return $query;
}
public function buildExists()
{
if( !isset( $this->data['exists'] ) )
{
return '';
}
// Determines if there's a where clause
$where = isset( $this->data['where'] ) ? $this->data[ 'where' ] : array();
$exists = $this->data[ 'exists' ];
$query = array();
$joiner = false;
$length = count( $exists );
for( $i = 0; $i < $length; $i++ )
{
if( count( $where ) > 0 )
{
$query[] = 'AND ' . $exists[ $i ];
}
else
{
$query[] = $exists[ $i ];
}
}
$query = count( $where ) > 0 ? implode( ' ', $query ) : ' WHERE ' . implode( ' ' , $query );
return $query;
}
private function buildCondition( $column, $value, $type = '=' )
{
$query = $this->parseColumnName( $column ) . ' ';
// type could be IN or NOT IN, value could be an array of values
if( stripos( $type, 'in' ) !== false )
{
if( !is_array( $value ) )
{
$value = array( $value );
}
foreach( $value as &$v )
{
$v = $this->quote( $v );
}
$query .= strtoupper( $type ) . ' (' . implode( ', ', $value ) . ')';
}
else
{
if( empty( $type ) )
{
$type = '=';
}
if( is_null( $value ) )
{
$value = 'NULL';
}
else
{
$value = $this->Quote( $value );
}
$query .= strtoupper( $type ) . ' ' . $value;
}
return $query;
}
private function buildJoin()
{
if (!isset($this->data['join'])) {
return '';
}
$query = array();
$join = $this->data['join'];
$iLength = count($join);
for ($i = 0; $i < $iLength; $i++) {
list($table, $alias, $type) = $join[$i];
$line = ' ' . strtoupper( $type ) . ' JOIN ' . $this->nameQuote( $table ) . ' AS ' . $this->nameQuote($alias);
if (isset($this->data['on']) && $this->data['on'][$i]) {
$line .= ' ON ';
$on = $this->data['on'][$i];
$joiner = false;
$jLength = count($on);
for ($j = 0; $j < $jLength; $j++) {
list( $columnA, $columnB, $onType, $onCondition ) = $on[$j];
// For second condition and above, we need the condition joiner
if ($joiner) {
$line .= ' ' . $onCondition . ' ';
} else {
$joiner = true;
}
if ($columnA === '(' || ( isset( $on[$j + 1 ] ) && $on[$j + 1][0] === ')')) {
$joiner = false;
}
if($columnA === '(' || $columnA === ')') {
$line .= $columnA;
} else {
if (empty($onType)) {
$onType = '=';
}
$line .= $this->parseColumnName( $columnA ) . ' ' . $onType . ' ';
// columnB could be a value rather than a column name
// 1. test for '.' to see if it is a column name
// 2. test for '"' to see if it is a column name since column names shouldn't contain "
if (strpos($columnB, '.') !== false && strpos($columnB, '"') === false) {
$line .= $this->parseColumnName($columnB);
} else {
if (strpos($columnB, '"') !== false) {
$columnB = str_ireplace('"', '', $columnB);
}
$line .= $this->quote($columnB);
}
}
}
}
$query[] = $line;
}
$query = implode( ' ', $query );
return $query;
}
private function buildGroup()
{
if( !isset( $this->data['group'] ) )
{
return '';
}
$group = $this->data['group'];
$query = array();
foreach( $group as $column )
{
$query[] = $this->parseColumnName( $column );
}
$query = count( $query ) > 0 ? ' GROUP BY ' . implode( ', ', $query ) : '';
return $query;
}
private function buildHaving()
{
if( !isset( $this->data['having'] ) )
{
return '';
}
// $this->data['having'][] = array( $column, $value, $type, $condition );
$having = $this->data['having'];
$query = array();
$joiner = false;
$iLength = count( $having );
for( $i = 0; $i < $iLength; $i++ )
{
list( $column, $value, $type, $condition ) = $having[$i];
$line = '';
// For second condition and above, prepend the where condition
if( $joiner )
{
$line = strtoupper( $condition ) . ' ';
}
else
{
$joiner = true;
}
if( $column === '(' || ( isset( $having[$i + 1 ] ) && $having[$i + 1][0] === ')' ) )
{
$joiner = false;
}
if( $column === '(' || $column === ')' )
{
$line .= $column;
}
else
{
$line .= $this->buildCondition( $column, $value, $type );
}
$query[] = $line;
}
$query = count( $query ) > 0 ? ' HAVING ' . implode( ' ', $query ) : '';
return $query;
}
private function buildOrder()
{
if( !isset( $this->data['order'] ) )
{
return '';
}
// $this->data['order'][] = array( $column, $direction );
$order = $this->data['order'];
$line = '';
$iLength = count( $order );
for( $i = 0; $i < $iLength; $i++ )
{
list( $column, $direction, $function ) = $order[$i];
if( !empty( $function ) )
{
$query[] = $this->parseFunction( $function, $column );
}
else
{
$line = $this->parseColumnName( $column );
$query[] = $line . ' ' . $direction;
}
}
$query = count( $query ) > 0 ? ' ORDER BY ' . implode( ',', $query ) : '';
return $query;
}
private function buildLimit()
{
if( !isset( $this->data['limit'] ) )
{
return '';
}
list( $start, $limit ) = $this->data['limit'];
$query = ' LIMIT ' . $start . ', ' . $limit;
return $query;
}
/**
* END OF INTERNAL BUILDING FUNCTIONS
*/
}