addQueryMethod('select', 'SELECT ', ', '); $this->addQueryMethod('from', " \nFROM `", '`,`', '` '); $this->addQueryMethod('join', " \nJOIN ", " \nJOIN "); $this->addQueryMethod('leftjoin', " \nLEFT JOIN ", " \nLEFT JOIN "); $this->addQueryMethod('orderby', " \nORDER BY ", ","); $this->addQueryMethod('groupby', " \nGROUP BY ", ','); $this->addQueryMethod('limit', " \nLIMIT ", ','); $this->set('comment', ''); } /** * Return the resulting SQL ready for execution with the database * */ public function getQuery() { $sql = trim( $this->getQueryMethod('select') . $this->getQueryMethod('from') . $this->getQueryMethod('join') . $this->getQueryMethod('leftjoin') . $this->getQueryMethod('where') . $this->getQueryMethod('groupby') . $this->getQueryMethod('orderby') . $this->getQueryMethod('limit') ) . ' '; if($this->get('comment') && $this->wire('config')->debug) { // NOTE: PDO thinks ? and :str param identifiers in /* comments */ are real params // so we str_replace them out of the comment, and only support comments in debug mode $comment = str_replace(array('*/', '?', ':'), '', $this->comment); $sql .= "/* $comment */"; } return $sql; } /** * Add an ORDER BY section to the query * * @param string|array $value * @param bool $prepend Should the value be prepended onto the existing value? default is to append rather than prepend. * Note that $prepend is applicable only when you pass this method a string. $prepend is ignored if you pass an array. * @return $this * */ public function orderby($value, $prepend = false) { if(is_object($value)) { if($value instanceof DatabaseQuerySelect) { $value = $value->orderby; } else { // invalid return $this; } } $oldValue = $this->get('orderby'); if(is_array($value)) { $this->set('orderby', array_merge($oldValue, $value)); } else if($prepend) { array_unshift($oldValue, $value); $this->set('orderby', $oldValue); } else { $oldValue[] = $value; $this->set('orderby', $oldValue); } return $this; } /** * Get SELECT portion of SQL * * @return string * */ protected function getQuerySelect() { if(self::$dbCache === null) { self::$dbCache = $this->wire('config')->dbCache === false ? false : true; } $select = $this->select; $sql = ''; // ensure that an SQL_CALC_FOUND_ROWS request comes first while(($key = array_search("SQL_CALC_FOUND_ROWS", $select)) !== false) { if(!$sql) $sql = "SELECT SQL_CALC_FOUND_ROWS "; unset($select[$key]); } if(!$sql) $sql = "SELECT "; if(self::$dbCache === false) $sql .= "SQL_NO_CACHE "; return $sql . implode(',', $select) . ' '; } /** * Get GROUP BY section of SQL * * @return string * */ protected function getQueryGroupby() { if(!count($this->groupby)) return ''; $sql = "\nGROUP BY "; $having = array(); foreach($this->groupby as $s) { // if it starts with 'HAVING' then we will determine placement // this is a shortcut to combine multiple HAVING statements with ANDs if(stripos($s, 'HAVING ') === 0) { $having[] = substr($s, 7); continue; } $sql .= "$s,"; } if(count($having)) { // place in any having statements that weren't placed $sql = rtrim($sql, ",") . " HAVING "; foreach($having as $n => $h) { if($n > 0) $sql .= " AND "; $sql .= $h; } } return rtrim($sql, ",") . " "; } /** * Get LIMIT section of SQL * * @return string * */ protected function getQueryLimit() { if(!count($this->limit)) return ''; $limit = $this->limit; $limit = reset($limit); if(strpos($limit, ',') !== false) { list($start, $limit) = explode(',', $limit); $start = (int) trim($start); $limit = (int) trim($limit); $limit = "$start,$limit"; } else { $limit = (int) $limit; } return "\nLIMIT $limit "; } }