diff --git a/src/Libs/ModelMySQL.php b/src/Libs/ModelMySQL.php index 51efa0d..a392e7e 100644 --- a/src/Libs/ModelMySQL.php +++ b/src/Libs/ModelMySQL.php @@ -1,7 +1,7 @@ ['*'], - 'where' => '', - 'from' => '', - 'leftJoin' => '', - 'rightJoin' => '', - 'innerJoin' => '', - 'AndOr' => '', - 'orderBy' => '', - 'groupBy' => '', - 'limit' => '', + 'select' => ['*'], + 'where' => '', + 'from' => '', + 'leftJoin' => '', + 'rightJoin' => '', + 'innerJoin' => '', + 'AndOr' => '', + 'orderBy' => '', + 'groupBy' => '', + 'limit' => '', + 'sql_calc_found_rows' => false ]; /* - * Sirve para obtener la instancia de la base de datos + * Sirve para obtener la instancia de la base de datos * * @return mysqli */ @@ -49,7 +50,7 @@ class ModelMySQL { return static::$db; } - + /* * Ejecuta una sentencia SQL en la base de datos. * @@ -64,7 +65,7 @@ class ModelMySQL { */ protected static function query($query) { $db = static::db(); - + $result = $db->query($query); if ($db->errno) { echo ''; @@ -75,38 +76,45 @@ class ModelMySQL { "Query: $query\n" ); } - + return $result; } - + /* * Reinicia la configuración de la sentencia SQL. */ protected static function resetQuery() { static::$querySelect = [ - 'select' => ['*'], - 'where' => '', - 'from' => '', - 'leftJoin' => '', - 'rightJoin' => '', - 'innerJoin' => '', - 'AndOr' => '', - 'orderBy' => '', - 'groupBy' => '', - 'limit' => '', + 'select' => ['*'], + 'where' => '', + 'from' => '', + 'leftJoin' => '', + 'rightJoin' => '', + 'innerJoin' => '', + 'AndOr' => '', + 'orderBy' => '', + 'groupBy' => '', + 'limit' => '', + 'sql_calc_found_rows' => false ]; } - + /* * Construye la sentencia SQL a partir static::$querySelect y una vez * construída, llama a resetQuery. * + * @param boolean $resetQuery + * Indica si el query debe reiniciarse o no (por defecto es true). + * * @return string * Contiene la sentencia SQL. */ - protected static function buildQuery() { - $sql = 'SELECT '.join(', ', static::$querySelect['select']); - + protected static function buildQuery($resetQuery = true) { + if (static::$querySelect['sql_calc_found_rows']) + $sql = 'SELECT SQL_CALC_FOUND_ROWS '.join(', ', static::$querySelect['select']); + else + $sql = 'SELECT '.join(', ', static::$querySelect['select']); + if (static::$querySelect['from'] != '') { $sql .= ' FROM '.static::$querySelect['from']; } else { @@ -116,40 +124,41 @@ class ModelMySQL { if(static::$querySelect['innerJoin'] != '') { $sql .= static::$querySelect['innerJoin']; } - + if (static::$querySelect['leftJoin'] != '') { $sql .= static::$querySelect['leftJoin']; - } - + } + if(static::$querySelect['rightJoin'] != '') { $sql .= static::$querySelect['rightJoin']; } - + if (static::$querySelect['where'] != '') { $sql .= ' WHERE '.static::$querySelect['where']; - + if (static::$querySelect['AndOr'] != '') { $sql .= static::$querySelect['AndOr']; } } - + if (static::$querySelect['groupBy'] != '') { $sql .= ' GROUP BY '.static::$querySelect['groupBy']; } - + if (static::$querySelect['orderBy'] != '') { $sql .= ' ORDER BY '.static::$querySelect['orderBy']; } - + if (static::$querySelect['limit'] != '') { $sql .= ' LIMIT '.static::$querySelect['limit']; } - - static::resetQuery(); - + + if ($resetQuery) + static::resetQuery(); + return $sql; } - + /* * Crea una instancia del objeto actual a partir de un arreglo. * @@ -163,11 +172,11 @@ class ModelMySQL { protected static function getInstance($elem = []) { $class = get_called_class(); $instance = new $class; - + foreach ($elem as $key => $value) { $instance->$key = $value; } - + return $instance; } @@ -175,27 +184,27 @@ class ModelMySQL { * @return array * Contiene los atributos indexados del objeto actual. */ - protected function getVars() { + protected function getVars() { $reflection = new \ReflectionClass($this); $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC); $result = []; - + foreach($properties as $property) { $att = $property->name; $result[$att] = $this->$att; } - + foreach (static::$ignoreSave as $del) { unset($result[$del]); } - + foreach (static::$forceSave as $value) { $result[$value] = $this->$value; } - + return $result; } - + /* * @return string * Devuelve el nombre de la clase actual @@ -203,12 +212,12 @@ class ModelMySQL { public static function className() { return strtolower(substr(strrchr(get_called_class(), '\\'), 1)); } - + /* - * Construye (a partir del nombre de la clase y el sufijo en static::$tableSufix) + * Construye (a partir del nombre de la clase y el sufijo en static::$tableSufix) * y/o develve el nombre de la tabla de la BD en la que se alojará o * se aloja el objeto actual. - * + * * @return string */ protected static function table() { @@ -222,7 +231,7 @@ class ModelMySQL { */ protected function update() { $atts = $this->getVars(); - + foreach ($atts as $key => $value) { if (isset($value)) { $value = static::db()->real_escape_string($value); @@ -235,14 +244,14 @@ class ModelMySQL { $set[]="$key=NULL"; } } - + $table = static::table(); $pk = static::$primaryKey; $pkv = $this->$pk; $sql = "UPDATE $table SET ".join(', ', $set)." WHERE $pk='$pkv'"; static::query($sql); } - + /* * Inserta una nueva fila en la base de datos a partir del * objeto actual. @@ -250,22 +259,22 @@ class ModelMySQL { protected function add() { $db = static::db(); $atts = $this->getVars(); - + foreach ($atts as $key => $value) { if (isset($value)) { $into[] = "`$key`"; $values[] = "'".$db->real_escape_string($value)."'"; } } - + $table = static::table(); $sql = "INSERT INTO $table (".join(', ', $into).") VALUES (".join(', ', $values).")"; static::query($sql); - + $pk = static::$primaryKey; $this->$pk = $db->insert_id; } - + /* * Revisa si el objeto a guardar es nuevo o no y según el resultado * llama a update para actualizar o add para insertar una nueva fila. @@ -277,25 +286,25 @@ class ModelMySQL { else $this->add(); } - + /* * Elimina el objeto actual de la base de datos. */ public function delete() { $atts = $this->getVars(); - + foreach ($atts as $key => $value) { $value = static::db()->real_escape_string($value); $set[]="$key='$value'"; } - + $table = static::table(); $pk = static::$primaryKey; $pkv = $this->$pk; $sql = "DELETE FROM $table WHERE $pk='$pkv'"; static::query($sql); } - + /* * Define SELECT en la sentencia SQL. * @@ -308,12 +317,12 @@ class ModelMySQL { foreach($columns as $column) { $select[] = $db->real_escape_string($column); } - + static::$querySelect['select'] = $select; - + return new static(); } - + /* * Define FROM en la sentencia SQL. * @@ -326,12 +335,12 @@ class ModelMySQL { foreach($tables as $table) { $from[] = $db->real_escape_string($table); } - + static::$querySelect['from'] = join(', ', $from); - + return new static(); } - + /* * Define el WHERE en la sentencia SQL. * @@ -347,7 +356,7 @@ class ModelMySQL { * @param $no_quote * Se usa cuando $value es una columna o un valor que no requiere comillas * - * Sintaxis posibles: + * Sintaxis posibles: * - static::where(columna, operador, valor) * - static::where(columna, valor) // Operador por defecto "=" */ @@ -356,17 +365,17 @@ class ModelMySQL { $value = $operator; $operator = '='; } - + $value = static::db()->real_escape_string($value); - + if ($no_quote) static::$querySelect['where'] = "$column$operator$value"; else static::$querySelect['where'] = "$column$operator'$value'"; - + return new static(); } - + /* * Define WHERE usando IN en la sentencia SQL. * @@ -383,15 +392,15 @@ class ModelMySQL { foreach($arr as $index => $value) { $arr[$index] = static::db()->real_escape_string($value); } - + if ($in) static::$querySelect['where'] = "$column IN (".join(', ',$arr).")"; else static::$querySelect['where'] = "$column NOT IN (".join(', ',$arr).")"; - + return new static(); } - + /* * Define LEFT JOIN en la sentencia SQL. * @@ -407,7 +416,7 @@ class ModelMySQL { * @param string $columnB * Columna a comparar para hacer el join. * - * Sintaxis posibles: + * Sintaxis posibles: * - static::leftJoin(tabla,columnaA, operador, columnB) * - static::leftJoin(tabla,columnaA, columnB) // Operador por defecto "=" */ @@ -416,16 +425,16 @@ class ModelMySQL { $columnB = $operator; $operator = '='; } - + $columnA = static::db()->real_escape_string($columnA); $columnB = static::db()->real_escape_string($columnB); - + static::$querySelect['leftJoin'] .= ' LEFT JOIN ' . $table . ' ON ' . "$columnA$operator$columnB"; - - + + return new static(); } - + /* * Define RIGHT JOIN en la sentencia SQL. * @@ -441,7 +450,7 @@ class ModelMySQL { * @param string $columnB * Columna a comparar para hacer el join. * - * Sintaxis posibles: + * Sintaxis posibles: * - static::rightJoin(tabla,columnaA, operador, columnB) * - static::rightJoin(tabla,columnaA, columnB) // Operador por defecto "=" */ @@ -450,15 +459,15 @@ class ModelMySQL { $columnB = $operator; $operator = '='; } - + $columnA = static::db()->real_escape_string($columnA); $columnB = static::db()->real_escape_string($columnB); - + static::$querySelect['rightJoin'] .= ' RIGHT JOIN ' . $table . ' ON ' . "$columnA$operator$columnB"; - + return new static(); } - + /* * Define INNER JOIN en la sentencia SQL. * @@ -474,7 +483,7 @@ class ModelMySQL { * @param string $columnB * Columna a comparar para hacer el join. * - * Sintaxis posibles: + * Sintaxis posibles: * - static::innerJoin(tabla,columnaA, operador, columnB) * - static::innerJoin(tabla,columnaA, columnB) // Operador por defecto "=" */ @@ -483,15 +492,15 @@ class ModelMySQL { $columnB = $operator; $operator = '='; } - + $columnA = static::db()->real_escape_string($columnA); $columnB = static::db()->real_escape_string($columnB); - + static::$querySelect['innerJoin'] .= ' INNER JOIN ' . $table . ' ON ' . "$columnA$operator$columnB"; - + return new static(); } - + /* * Define AND en la sentencia SQL (se puede anidar). * @@ -507,7 +516,7 @@ class ModelMySQL { * @param $no_quote * Se usa cuando $value es una columna o un valor que no requiere comillas * - * Sintaxis posibles: + * Sintaxis posibles: * - static::and(columna, operador, valor) * - static::and(columna, valor) // Operador por defecto "=" * - static::and(columna, valor)->and(columna, valor)->and(columna, valor) // anidado @@ -517,17 +526,17 @@ class ModelMySQL { $value = $operator; $operator = '='; } - + $value = static::db()->real_escape_string($value); - + if ($no_quote) static::$querySelect['AndOr'] .= " AND $column$operator$value"; else static::$querySelect['AndOr'] .= " AND $column$operator'$value'"; - + return new static(); } - + /* * Define OR en la sentencia SQL (se puede anidar). * @@ -543,7 +552,7 @@ class ModelMySQL { * @param $no_quote * Se usa cuando $value es una columna o un valor que no requiere comillas * - * Sintaxis posibles: + * Sintaxis posibles: * - static::or(columna, operador, valor) * - static::or(columna, valor) // Operador por defecto "=" * - static::or(columna, valor)->or(columna, valor)->or(columna, valor) // anidado @@ -553,17 +562,17 @@ class ModelMySQL { $value = $operator; $operator = '='; } - + $value = static::db()->real_escape_string($value); - + if ($no_quote) static::$querySelect['AndOr'] .= " OR $column$operator$value"; else static::$querySelect['AndOr'] .= " OR $column$operator'$value'"; - + return new static(); } - + /* * Define GROUP BY en la sentencia SQL * @@ -574,27 +583,27 @@ class ModelMySQL { static::$querySelect['groupBy'] = join(', ', $arr); return new static(); } - + public static function limit($initial, $final = 0) { $initial = (int)$initial; $final = (int)$final; - + if ($final==0) static::$querySelect['limit'] = $initial; else static::$querySelect['limit'] = $initial.', '.$final; - + return new static(); } - + /* * Define ORDER BY en la sentencia SQL * * @param string $value * Columna por la que se ordenará. - * + * * @param string $order - * Define si el orden será de manera ascendente (ASC), + * Define si el orden será de manera ascendente (ASC), * descendente (DESC) o aleatorio (RAND). */ public static function orderBy($value, $order = 'ASC') { @@ -602,42 +611,64 @@ class ModelMySQL { static::$querySelect['orderBy'] = 'RAND()'; return new static(); } - + $value = static::db()->real_escape_string($value); - + if (!(strtoupper($order) == 'ASC' || strtoupper($order) == 'DESC')) - $order = 'ASC'; - + $order = 'ASC'; + static::$querySelect['orderBy'] = $value.' '.$order; - + return new static(); } - + /* * Retorna la cantidad de filas que hay en un query. * + * @param boolean $resetQuery + * Indica si el query debe reiniciarse o no (por defecto es true). + * * @return int */ - public static function count() { - if (static::$querySelect['select'] == ['*']) - static::$querySelect['select'] = ['count(*) as quantity']; - else - static::$querySelect['select'][] = 'count(*) as quantity'; - $sql = static::buildQuery(); + public static function count($resetQuery = true) { + static::$querySelect['select'] = ['1']; + static::$querySelect['sql_calc_found_rows'] = true; + static::$querySelect['limit'] = '1'; + $sql = static::buildQuery($resetQuery); $result = static::query($sql)->fetch_assoc(); + return static::found_row(); + } + + /* + * Retorna las filas contadas en el último query. + * + * @return int + */ + public static function found_row() { + $result = static::query('SELECT FOUND_ROWS() AS quantity')->fetch_assoc(); return $result['quantity']; } - + /* - * Obtiene una instancia según su id. + * Habilita el conteo de todos las coincidencias posibles incluso usando limit. + * + * @return ModelMySQL + */ + public static function sql_calc_found_rows() { + static::$querySelect['sql_calc_found_rows'] = true; + return new static(); + } + + /* + * Obtiene una instancia según su primary key (generalmente id). * - * @param int $id + * @param mixed $id * @return ModelMySQL */ public static function getById($id) { return static::where(static::$primaryKey, $id)->getFirst(); } - + /* * Realiza una búsqueda en la tabla de la instancia actual. * @@ -652,52 +683,58 @@ class ModelMySQL { $className = get_called_class(); $in = array_keys((new $className())->getVars()); } - + $db = static::db(); - + $search = $db->real_escape_string($search); - + $where = []; - + foreach($in as $row) { $where[] = "$row LIKE '%$search%'"; } - + if (static::$querySelect['where']=='') static::$querySelect['where'] = join(' OR ', $where); else static::$querySelect['where'] = static::$querySelect['where'] .' AND ('.join(' OR ', $where).')'; - + return new static(); } - + /* * Obtener los resultados de la consulta SQL. * + * @param boolean $resetQuery + * Indica si el query debe reiniciarse o no (por defecto es true). + * * @return ModelMySQL[] */ - public static function get() { // Devuelve array vacío si no encuentra nada - $sql = static::buildQuery(); + public static function get($resetQuery = true) { // Devuelve array vacío si no encuentra nada + $sql = static::buildQuery($resetQuery); $result = static::query($sql); - + $instances = []; - + while ($row = $result->fetch_assoc()) { $instances[] = static::getInstance($row); } - + return $instances; } - + /* * El primer elemento de la consulta SQL. * + * @param boolean $resetQuery + * Indica si el query debe reiniciarse o no (por defecto es true). + * * @return mixed * Puede retornar un objeto ModelMySQL o null. */ - public static function getFirst() { // Devuelve null si no encuentra nada + public static function getFirst($resetQuery = true) { // Devuelve null si no encuentra nada static::limit(1); - $instances = static::get(); + $instances = static::get($resetQuery); return empty($instances) ? null : $instances[0]; } @@ -708,15 +745,15 @@ class ModelMySQL { */ public static function all() { $sql = 'SELECT * FROM '.static::table(); - + $result = static::query($sql); - + $instances = []; - + while ($row = $result->fetch_assoc()) { $instances[] = static::getInstance($row); } - + return $instances; } @@ -731,7 +768,7 @@ class ModelMySQL { throw new \Exception( "\nEl método setNull sólo funciona para actualizar, no al insertar." ); - + foreach ($atts as $att) { if (!in_array($att, $this->toNull)) $this->toNull[] = $att;