skipLineBreak($query); if(empty($query)) return; $this->parser = new PhpMyAdmin\SqlParser\Parser($query); $this->statements = $this->parser->statements; $this->statementsCount = count($this->statements); $this->statement = $this->statementsCount > 0 ? current($this->statements) : null; $this->isSelect = $this->statement instanceof PhpMyAdmin\SqlParser\Statements\SelectStatement === true; } /** * Set dao. * * @param object $dao * @access public * @return void */ public function setDAO($dao) { $this->dao = $dao; } /** * Parse statement. * * @access public * @return void */ public function parseStatement() { if(empty($this->statement)) return; $this->columns = $this->parseColumns(); $this->tables = $this->parseTables(); } /** * Create statement. * * @access public * @return void */ public function createStatement() { $this->statement = new PhpMyAdmin\SqlParser\Statements\SelectStatement(); } /** * Set from. * * @param object $from * @access public * @return void */ public function setFrom($from) { $this->statement->from = array($from); } /** * Add select. * * @param array|object $exprs * @access public * @return void */ public function addSelect($exprs) { if(empty($exprs)) return; if($exprs instanceof PhpMyAdmin\SqlParser\Components\Expression) { $this->statement->expr[] = $exprs; return; } foreach($exprs as $expr) $this->addSelect($expr); } /** * Add join. * * @param array|object $joins * @access public * @return void */ public function addJoin($joins) { if(empty($joins)) return; if($joins instanceof PhpMyAdmin\SqlParser\Components\JoinKeyword) { $this->statement->join[] = $joins; return; } foreach($joins as $join) $this->addJoin($join); } /** * Add where. * * @param array|object $wheres * @access public * @return void */ public function addWhere($wheres) { if(empty($wheres)) return; if($wheres instanceof PhpMyAdmin\SqlParser\Components\Condition) { $this->statement->where[] = $wheres; return; } foreach($wheres as $where) $this->addWhere($where); } /** * Add group. * * @param array|object $groups * @access public * @return void */ public function addGroup($groups) { if(empty($groups)) return; if($groups instanceof PhpMyAdmin\SqlParser\Components\GroupKeyword) { $this->statement->group[] = $groups; return; } foreach($groups as $group) $this->addGroup($group); } /** * Get function. * * @param string $name * @param mixed $args * @access public * @return string */ public function getFunction($name, ...$args) { $name = strtoupper($name); $argStr = implode(', ', $args); $argStr = str_replace(PHP_EOL, '', $argStr); return "$name($argStr)"; } /** * Get expression. * * @param string|array $table * @param string $column * @param string $alias * @param string $function * @access public * @return PhpMyAdmin\SqlParser\Components\Expression */ public function getExpression($table = null, $column = null, $alias = null, $function = null) { if(is_array($table)) return call_user_func_array(array($this, 'getExpression'), $table); $expression = new PhpMyAdmin\SqlParser\Components\Expression(); if(!empty($function)) { $expression->function = $function; $expression->expr = $this->getFunction($function, $expression->build($this->getExpression($table, $column))); } else { if($column === '*') { $table = $this->trimExpr($table); $expression->expr = empty($table) ? '*' : "`$table`.*"; } else { $expression->table = $table; $expression->column = $column; } } $expression->alias = $alias; return $expression; } /** * operatorCondition * * @param string $type * @access public * @return void */ public function operatorCondition($type) { $condition = new PhpMyAdmin\SqlParser\Components\Condition(); $condition->isOperator = true; $condition->expr = strtoupper($type); return $condition; } /** * Get condition. * * @param mixed $tableA * @param mixed $columnA * @param string $operator * @param mixed $tableB * @param mixed $columnB * @param mixed $group * @access public * @return object */ public function getCondition($tableA = null, $columnA = null, $operator = '', $tableB = null, $columnB = null, $group = 1, $quote = true) { if(is_array($tableA)) return call_user_func_array(array($this, 'getCondition'), $tableA); $condition = new PhpMyAdmin\SqlParser\Components\Condition(); $tableA = $this->trimExpr($tableA); $columnA = $this->trimExpr($columnA); $tableB = $this->trimExpr($tableB); $expr = ''; if(empty($operator)) { $expr = $columnA; } else { /* 如果tableB不为空,那么columnB就是字段,需要trim('`')。*/ if(!empty($tableB)) $columnB = $this->trimExpr($columnB); /* 如果tableB为空,那么columnB是值,需要trim("'")。*/ if(empty($tableB)) $columnB = $this->trimExpr($columnB, "'"); $columnB = empty($tableB) && $quote ? "'$columnB'" : $columnB; $exprA = empty($tableA) ? "`$columnA`" : "`$tableA`.`$columnA`"; $exprB = empty($tableB) ? $columnB : "`$tableB`.`$columnB`"; $operator = strtoupper($operator); $expr = "$exprA $operator $exprB"; } $condition->expr = $expr; $condition->group = $group; return $condition; } /** * Get conditions from array. * * @param array $conditions * @access public * @return array */ public function getConditionsFromArray($conditions) { if(is_string($conditions)) return $this->operatorCondition($conditions); $first = current($conditions); if(!is_array($first) && !in_array($first, array('and', 'or'))) return $this->getCondition($conditions); $conditionExprs = array(); foreach($conditions as $condition) $conditionExprs[] = $this->getConditionsFromArray($condition); return $conditionExprs; } /** * Get left join. * * @param string $table * @param string $alias * @param array $on * @access public * @return object */ public function getLeftJoin($table, $alias, $on) { $left = new PhpMyAdmin\SqlParser\Components\JoinKeyword(); $left->type = 'LEFT'; $left->expr = $this->getExpression($table, null, $alias); $left->on = $this->combineConditions($on); return $left; } /** * Get group. * * @param object $expr * @access public * @return void */ public function getGroup($expr) { $group = new PhpMyAdmin\SqlParser\Components\GroupKeyword(); $group->expr = $expr; return $group; } /** * Combine conditions. * * @param array|object $conditions * @access public * @return array */ public function combineConditions($conditions, $quote = false) { if(empty($conditions)) return array(); if($conditions instanceof PhpMyAdmin\SqlParser\Components\Condition === true) return $conditions; $first = reset($conditions); $last = end($conditions); if($quote) { $first = $this->addQuote($first, 'left'); $last = $this->addQuote($last, 'right'); } $quote = true; if(is_array($first)) $first = $this->combineConditions($first, $quote); if(is_array($last)) $last = $this->combineConditions($last, $quote); $conditions[0] = $first; $conditions[count($conditions) - 1] = $last; return $conditions; } public function addQuote($conditions, $side) { if($conditions instanceof PhpMyAdmin\SqlParser\Components\Condition === true) { $expr = $conditions->expr; $conditions->expr = $side == 'left' ? '(' . $expr : $expr . ')'; return $conditions; } $condition = $side == 'left' ? current($conditions) : end($conditions); $index = $side == 'left' ? 0 : count($conditions) - 1; $conditions[$index] = $this->addQuote($condition, $side); return $conditions; } /** * Match columns with table. * * @access public * @return array */ public function matchColumnsWithTable() { if(empty($this->statement)) return array(); if(count($this->tables) == 1) return $this->combineSingleTable(); return $this->combineMultipleTable(); } /** * Trim expr. * * @param string $expr * @access private * @return string */ private function trimExpr($expr, $char = '`') { if(empty($expr)) return $expr; return trim(trim($expr), $char); } /** * Combine single table to columns. * * @access private * @return array */ private function combineSingleTable() { $combineColumns = array(); $fromTable = current($this->tables); foreach($this->columns as $columnName => $column) { $column['table'] = array_merge($fromTable, array('column' => $column['origin'])); $combineColumns[$columnName] = $column; } return $combineColumns; } /** * Combine multiple table to columns. * * @access private * @return array */ private function combineMultipleTable() { foreach($this->columns as $columnName => $column) { $column['table'] = $this->searchTables($column['table'], $this->tables, $column['origin']); $combineColumns[$columnName] = $column; } return $combineColumns; } /** * Search table from origin tables. * * @param string $tableName * @param string $tables * @param string $column * @access private * @return string|false */ private function searchTables($tableName, $tables, $column) { /* 如果能使用别名匹配上,那么直接返回。*/ /* If it can be matched using an alias, then it returns. */ foreach($tables as $table) if($tableName == $table['alias']) return array_merge($table, array('column' => $column)); /* 如果匹配不上,则字段没有使用别名进行限制,那么需要通过字段去遍历所有表。*/ /* If it doesn't match, then the field is not aliased, and you need to iterate over all tables using the field. */ foreach($tables as $table) { $isTable = $table['isTable']; $originTable = $table['originTable']; /* 如果是原始表,并且列在原始表中存在,那么返回这个表。*/ /* If it is the original table and the column exists in the original table, then the table is returned. */ if($isTable && $this->columnExistInOriginTable($originTable, $column)) return array_merge($table, array('column' => $column)); /* 如果不是原始表,并且列在子句中存在,那么返回子句中这个字段对应的表。*/ /* If it is not the original table and the column exists in the clause, then the table corresponding to the field in the clause is returned. */ if(!$isTable && isset($originTable[$column])) return array_merge($originTable[$column]['table'], array('column' => $originTable[$column]['origin'])); } return false; } /** * Parse columns. * * @access private * @return void */ private function parseColumns() { $fields = array(); foreach($this->statement->expr as $expr) { /* 获取查询数据后真正展示出来的列名 */ $columnName = empty($expr->alias) ? $expr->column : $expr->alias; $fields[$columnName] = array('origin' => $expr->column, 'table' => $expr->table); } return $fields; } /** * Parse tables. * * @access private * @return void */ private function parseTables() { $from = current($this->statement->from); $joins = $this->statement->join; $tables = array(); $tables[] = $this->parseTable($from, 'from'); if(!empty($joins)) foreach($joins as $join) $tables[] = $this->parseTable($join->expr, 'join'); return $tables; } /** * Parse table. * * @param object $expr * @param string $type * @access private * @return void */ private function parseTable($expr, $type) { $isTable = empty($expr->subquery); $table = array('alias' => $expr->alias, 'isTable' => $isTable, 'type' => $type); $table['originTable'] = $this->getOriginTable($expr->expr, $isTable); return $table; } /** * Get origin table from table name or expr. * * @param string $table * @param bool $isTable * @access private * @return string|array */ private function getOriginTable($table, $isTable) { if(!$isTable) { $parser = new sqlparser($table); $parser->setDAO($this->dao); $parser->parseStatement(); return $parser->matchColumnsWithTable(); } $this->storeOriginTable($table); return $table; } /** * Judge column exist in origin table or not. * * @param string $table * @param string $column * @access private * @return bool */ private function columnExistInOriginTable($table, $column) { $originTable = $this->getOriginTableColumns($table); if(!$originTable) return false; return isset($originTable[$column]); } /** * Get origin table columns. * * @param string $table * @access private * @return array|null */ private function getOriginTableColumns($table) { $originTables = $this->originTables; return isset($originTables[$table]) ? $originTables[$table] : null; } /** * Store origin table. * * @param string $table * @access private * @return void */ private function storeOriginTable($table) { if(!isset($this->originTables[$table])) $this->originTables[$table] = $this->dao->descTable($table); } /** * Skip line break in sql. * * @param string $sql * @access private * @return string */ private function skipLineBreak($sql) { if(empty($sql)) return $sql; $sql = str_replace("\n\t", " ", $sql); $sql = str_replace("\t\n", " ", $sql); $sql = str_replace("\n\r", " ", $sql); $sql = str_replace("\r\n", " ", $sql); $sql = str_replace("\r", " ", $sql); $sql = str_replace("\n", " ", $sql); return $sql; } }