type = isset($options[$c = Query::TYPE]) ? $options[$c] : eQueryType::SELECT; $this->setTables( isset($options[$c = Query::TABLES]) ? $options[$c]: null); $this->setSort( isset($options[$c = Query::SORT]) ? $options[$c]: null); $this->setSelect( isset($options[$c = Query::SELECT]) ? $options[$c]: null); $this->setGroupBy( isset($options[$c = Query::GROUP_BY]) ? $options[$c]: null); $this->setOnDuplicateKeyUpdate( isset($options[$c = Query::ON_DUPLICATE_KEY_UPDATE]) ? $options[$c]: null); $this->setLeftJoins( isset($options[$c = Query::LEFT_JOINS]) ? $options[$c]: null); $this->setInnerJoins( isset($options[$c = Query::INNER_JOINS]) ? $options[$c]: null); $this->count = isset($options[$c = Query::COUNT]) ? intval($options[$c]) : 0; $this->offset = isset($options[$c = Query::OFFSET]) ? intval($options[$c]) : 0; $this->table = isset($options[$c = Query::TABLE]) ? $options[$c] : null; $this->values = isset($options[$c = Query::VALUES]) ? $options[$c] : []; $this->calc = isset($options[$c = Query::CALC]) ? boolval($options[$c]) : false; $this->column = isset($options[$c = Query::COLUMN]) ? (string)trim($options[$c]) : false; if(isset($options[$c = Query::WHERE])) { $this->where = $options[Query::WHERE]; if (is_array($this->where)) { $this->where = new \Where($this->where); //$o[Query::WHERE] = new \Where($this->where); } } $this->options = $options; //echo '
'.$this.'
'; //echo "\n".$this."\n"; } function __toString() { $q = []; // Тип запроса $q[] = eQueryType::toString( $this->type ); switch ($this->type) { case eQueryType::DROP_COLUMN: $table = $this->table; $q[] = DB::quotes($table->getName())." DROP ".DB::quotes($this->column); break; case eQueryType::ADD_COLUMN: $table = $this->table; $cols = $table->getColumns(); $col = $cols[$this->column]; $q[] = DB::quotes($table->getName())." ADD ".$col->toStringForCreateTable(); break; case eQueryType::DROP: $table = $this->table; $q[] = 'TABLE '.DB::quotes($table->getName()); break; case eQueryType::UPDATE: $table = $this->table; $values = $this->values; $where = $this->whereToString(); $columns = []; $cols = $table->getColumns(); $names = $table->columnNames(); foreach ($values as $k=>$v){ if(in_array($k,$names)) { if(is_array($v)) { $columns[] = DB::quotes($k) . "=" . $v['value'] . ""; } else { // проверяем тип колонки и проверяем присланные данные на соответствующий формат данных $isGood = true; switch ($cols[$k]->getType()) { case eColumnType::NONE: $isGood = false; break; case eColumnType::TINYINT: case eColumnType::INT: case eColumnType::BIGINT: case eColumnType::DOUBLE: $v = ($v ? "'" . DB::mq($v) . "'" : ($cols[$k]->isNull() ? 'NULL' : "'0'") ); break; case eColumnType::DATE: if ($v) { $v = "'" . DB::mq($v) . "'"; } else { $v = $cols[$k]->isNull() ? 'NULL' : "'0000-00-00'"; } break; default: if (!is_array($v)) { $v = ($v ? "'" . DB::mq($v) . "'" : ($cols[$k]->isNull() ? 'NULL' : "''") ); } } if ($isGood) { if (is_array($v)) { $columns[] = DB::quotes($k) . "=" . $v['value'] . ""; } else { $columns[] = DB::quotes($k) . "=" . $v; } } } } if($k==self::COLUMNS_INCREMENT){ foreach ($v as $inc_column=>$inc_value) { if(in_array($inc_column,$names)) { $inc_value = intval($inc_value); $columns[] = DB::quotes($inc_column)."=".DB::quotes($inc_column).($inc_value>0?'+':'-').abs($inc_value); } else if(in_array($inc_value,$names)) { $columns[] = DB::quotes($inc_value)."=".DB::quotes($inc_value).'+1'; } } } } $q[] = Db::quotes($table->getName()); $q[] = 'SET '.implode(",",$columns); $q[] = $where; break; case eQueryType::INSERT: $table = $this->table; $cols = $table->getColumns(); $values = $this->values; $columns = array(); foreach ($table->getColumns() as $k=>$v){ $value = isset($values[$k]) ? $values[$k] : $v->getDefault(); $isGoodColumn = true; // проверяем тип колонки и проверяем присланные данные на соответствующий формат данных switch ($cols[$k]->getType()){ case eColumnType::NONE: $isGoodColumn = false; break; case eColumnType::DATE: if($value) { $value = "'" . DB::mq($value) . "'"; } else { $value = $cols[$k]->isNull() ? "NULL" : "'0000-00-00'"; } break; case eColumnType::TINYINT: case eColumnType::INT: case eColumnType::BIGINT: case eColumnType::DOUBLE: if(!$value) { $v->getDefault(); } if(!$value) { $value = 0; } $value = cfloatval($value); switch ($cols[$k]->getType()){ case eColumnType::INT: case eColumnType::BIGINT: $value = intval($value); break; } $value = ( $value ? "'" . DB::mq($value) . "'" : ($cols[$k]->isNull() ? 'NULL' : '0') ); break; default: $value = ( $value ? "'" . DB::mq($value) . "'" : ($cols[$k]->isNull() ? 'NULL' : "''") ); } if ($isGoodColumn) { $columns[DB::quotes($v->getName())] = $value;//"'" . DB::mq($value) . "'"; } } $q[] = ' INTO '.Db::quotes($table->getName()).' ('.implode(",",array_keys($columns)).') VALUES('.implode(",",array_values($columns)).')'; $q[] = $this->onDuplicateKeyUpdateToSting(); break; case eQueryType::CREATE: $table = $this->table; if($table) { $columns = array(); $primary = null; $uniques = []; /** * @var $k * @var \core\db\structure\Column $v */ foreach ($table->getColumns() as $k=>$v){ $isGoodColumn = true; switch ($v->getType()) { case eColumnType::NONE: $isGoodColumn = false; break; } if($isGoodColumn) { $columns[] = $v->toStringForCreateTable(); if ($v->getPrimary()) $primary = $v; if ($v->getUnique()) $uniques[] = " UNIQUE (" . DB::quotes($v->getName()) . ")"; } } if($primary) $columns[] = 'PRIMARY KEY ('.Db::quotes($primary->getName()).')'; if($uniques) $columns[] = implode(",",$uniques); $q[] = 'TABLE IF NOT EXISTS '.DB::quotes($table->getName()).' ('.implode(",",$columns).') ENGINE=InnoDB DEFAULT CHARSET='.Config::$MYSQL_CHARSET; //echo implode(" ",$q).'
'; } break; default: $select = $this->selectToString(); // Если укзаны таблицы, указываем их через запятую $tables = $this->tablesToString(); // Определяем сортировку, если она конечно, есть $sort = $this->sortToString(); $limit = $this->limitToString(); $where = $this->whereToString(); $leftJoins = $this->leftJoinsToString(); $innerJoins = $this->innerJoinsToString(); $groupBy = $this->groupByToString(); if($this->type===eQueryType::SELECT) $q[]=$select; $q[] = $tables; $q[] = $leftJoins; $q[] = $innerJoins; $q[] = $where; $q[] = $groupBy; $q[] = $sort; $q[] = $limit; } return implode(" ",$q); } //----------------------------------- // МЕТОДЫ //----------------------------------- function execute(){ $this->result = DB::execute($this); return $this->result; } function toJSON(){ $res = []; foreach ($this->options as $k=>$v){ $isSet = true; switch ($k) { case self::TABLE: $isSet = false; break; case self::WHERE: $v = $v->toJSON(); break; } if($isSet) $res[$k] = $v; } unset($res[self::TABLE]); return $res; } /** * Функция для заданий новых таблиц в запросе * @param $tables array | string Таблицы */ function setTables($tables) { $this->tables = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($tables)) { foreach ($tables as $v){ $this->tables[] = (string)$v; } } else if($tables) $this->tables[] = (string)$tables; } function setSelect($select) { $this->select = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($select)) { foreach ($select as $v){ $this->select[] = (string)$v; } } else if($select) $this->select[] = (string)$select; } function setGroupBy($group_by) { $this->group_by = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($group_by)) { foreach ($group_by as $v){ $this->group_by[] = (string)$v; } } else if($group_by) $this->group_by[] = (string)$group_by; } function setOnDuplicateKeyUpdate($array) { $this->on_duplicate_key_update = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($array)) { foreach ($array as $k=>$v){ $this->on_duplicate_key_update[$k] = (string)$v; } } } function setLeftJoins($array) { $this->left_joins = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($array)) { foreach ($array as $k=>$v){ $this->left_joins[$k] = $v; /* //var_dump($v[0]); if (is_array($v)){ foreach ($v as $k1 => $v1) { $this->left_joins[$k][] = $v; } } else { $this->left_joins[$k] = $v; } /**/ } } else if($array) $this->left_joins[] = (string)$array; } function setInnerJoins($array) { $this->inner_joins = []; // Если это массив, то заносим значения в виде строк // Иначе заносим как строку if(is_array($array)) { foreach ($array as $k=>$v){ $this->inner_joins[$k] = $v; /* //var_dump($v[0]); if (is_array($v)){ foreach ($v as $k1 => $v1) { $this->left_joins[$k][] = $v; } } else { $this->left_joins[$k] = $v; } /**/ } } else if($array) $this->inner_joins[] = (string)$array; } /** * Функция для задания новой сортировки в столбце * @param $sort array | string */ function setSort($sort){ // Определяем сортировку // Если передан массив, то проходимся по нему. Ключ - это столбец, значение - тип сортировки. По умолчанию ASC if(is_array($sort)) { foreach ( $sort as $k=>$v) { if(is_numeric($k)){ $this->sort[$v] = eQuerySortType::ASC; } else { $this->sort[(string)$k] = eQuerySortType::check($v); } } } else if($sort) $this->sort[ (string)$sort ] = eQuerySortType::ASC; } /** * Публичная функция для получения запроса в формате строки * @return string */ function getQueryString():string{return $this->__toString();} //----------------------------------- // STATIC FUNCTIONS //----------------------------------- static function select(array $o){ $o[ self::TYPE ] = eQueryType::SELECT; return new Query($o); } static function delete(string $table, array $o){ $o[ self::TYPE ] = eQueryType::DELETE; $o[ self::TABLES ] = $table; return new Query($o); } static function insert(Table $table, $values = array(),array $o = array()){ $o[ self::TYPE ] = eQueryType::INSERT; $o[ self::TABLE ] = $table; $o[ self::VALUES ] = $values; return new Query($o); } static function update(\Table $table, array $o){ $o[ self::TYPE ] = eQueryType::UPDATE; $o[ self::TABLE ] = $table; return new Query($o); } static function createTable(\Table $table){ $o[ self::TYPE ] = eQueryType::CREATE; $o[ self::TABLE ] = $table; return new Query($o); } static function dropTable(\Table $table){ $o[ self::TYPE ] = eQueryType::DROP; $o[ self::TABLE ] = $table; return new Query($o); } //----------------------------------- // PROTECTED FUNCTIONS //----------------------------------- protected function whereToString(){ return ($this->where)?(string)$this->where:''; } protected function quoteTableColumn($column_data){ if($this->table) { $info = $this->table->getColumns(); $keys = array_keys($info); if (in_array($column_data, $keys)) { return \DB::quotes($column_data); } else { return "'".\DB::mq($column_data)."'"; } } else { return \DB::quotes($column_data); } } protected function innerJoinsToString(){ $res = ''; if($this->inner_joins) { foreach ($this->inner_joins as $v){ $res .= 'INNER JOIN ('.$v[0].') AS '.$v[1].' ON '.$v[2].'='.$v[3].' '; } } return $res; } protected function leftJoinsToString(){ if($this->left_joins) { $lefts = []; foreach ($this->left_joins as $k=>$v){ if(is_array($v)){ $columns = []; if(is_array($v[1])){ foreach ($v[1] as $ck=>$cv){ if(is_array($cv) and is_numeric($cv[0])){ switch ($cv[0]){ case \Where::BETWEEN: $columns[] = substr((string)new \Where(\Where::_between($cv[1],$cv[2],$cv[3])),5); break; case \Where::AND: $columns[] = substr((string)new \Where(\Where::_and($cv[1])),5); break; } } else { if (is_array($v[0])) { $columns[] = DB::quotes($ck) . '=' . $v[0][1] . '.' . $this->quoteTableColumn($cv); } else { $columns[] = DB::quotes($ck) . '=' . $this->quoteTableColumn($cv); } } } $columns = implode(' AND ',$columns); } else { if (is_array($v[0])) { $columns = DB::quotes($v[1])."=".DB::quotes($v[0][1]).".".db::quotes($v[2]); } else { $columns = DB::quotes($v[1])."=".db::quotes($v[2]); } } /* if (is_array($v[0])){ $lefts[] = "LEFT JOIN ".DB::quotes($v[0][0])." AS ".$v[0][1]." ON ".DB::quotes($v[1])."=".DB::quotes($v[0][1]).".".db::quotes($v[2]); } else { $lefts[] = "LEFT JOIN ".DB::quotes($v[0])." ON ".DB::quotes($v[1])."=".db::quotes($v[2]); } /**/ if (is_array($v[0])){ $lefts[] = "LEFT JOIN ".DB::quotes($v[0][0])." AS ".$v[0][1]." ON ".$columns; } else { $lefts[] = "LEFT JOIN ".DB::quotes($v[0])." ON ".$columns; } } else if(is_string($v)){ $lefts[] = $v; } } return implode(" ",$lefts); } else return ''; } /** * Фнукция для генерация LIMIT в троку * @return string */ protected function limitToString() : string{ $res = ''; if($this->count) { $res = ' LIMIT '.$this->count.( $this->offset ? ' OFFSET '.$this->offset : ''); } return $res; } /** * Фнукция для генерация списка таблиц в строку * @return string */ protected function tablesToString() : string{ if($this->tables) { $res = implode(",",$this->tables); switch ($this->type) { case eQueryType::SELECT: case eQueryType::DELETE: $res = "FROM ".$res; break; } return $res; } else return ''; } protected function selectToString() : string{ $res = $this->calc ? ' SQL_CALC_FOUND_ROWS ' : ''; if($this->select) { $res .= implode(",",$this->select); return $res; } else return $res.'*'; } protected function groupByToString() : string{ $res = ''; if($this->group_by) { $res .= ' GROUP BY '.implode(",",$this->group_by); return $res; } else return ''; } protected function onDuplicateKeyUpdateToSting(){ if($this->on_duplicate_key_update) { $res = 'ON DUPLICATE KEY UPDATE '; $cols = []; foreach ($this->on_duplicate_key_update as $k=>$v){ $cols[] = $k."='".DB::mq($v)."'"; } return $res.implode(",",$cols); } else return ''; } /** * Функция генерация сортировки в строку * @return string */ protected function sortToString() : string{ $res = ''; // Определяем сортировку, если она конечно, есть и если она нужна switch ($this->type) { case eQueryType::SELECT: if($this->sort) { $sort = []; foreach ($this->sort as $k=>$v) $sort[] = $k.' '.$v; $res = ' ORDER BY '.implode(",",$sort); } break; default:; } return $res; } }