Migrate to strong typed (compatible only with PHP 7.0+).

This commit is contained in:
kj 2022-03-17 17:22:04 -04:00
parent 503efef448
commit f43028d72d
4 changed files with 120 additions and 71 deletions

View File

@ -2,7 +2,7 @@
/*
* DuckBrain - Microframework
*
* Clase diseñada para crear y devolver una única instancia mysqli.
* Clase diseñada para crear y devolver una única instancia mysqli (database).
* Depende de manera forzada de que estén definidas las constantes:
* dbhost, dbname, dbpass y dbuser
*
@ -12,15 +12,21 @@
*/
namespace Libs;
use mysqli;
class Database {
class Database extends \mysqli {
static private $db;
private function __construct() {}
static public function getConnection() {
/**
* Devuelve una instancia homogénea (singlenton) a la base de datos.
*
* @return mysqli
*/
static public function getConnection() : mysqli {
if (!isset(self::$db)) {
self::$db = new \mysqli(dbhost, dbuser, dbpass, dbname);
self::$db = new mysqli(dbhost, dbuser, dbpass, dbname);
if (self::$db->connect_errno) {
echo '<style>body{white-space: pre-line;}</style>';
throw new \Exception('No se ha podido conectar a la base de datos.');

View File

@ -13,6 +13,7 @@
namespace Libs;
use Libs\Database;
use mysqli;
class ModelMySQL {
@ -44,7 +45,7 @@ class ModelMySQL {
*
* @return mysqli
*/
protected static function db() {
protected static function db() : mysqli {
if (is_null(static::$db))
static::$db = Database::getConnection();
@ -63,7 +64,7 @@ class ModelMySQL {
* @return mysqli_result
* Contiene el resultado de la llamada SQL.
*/
protected static function query($query) {
protected static function query($query) : mysqli_result {
$db = static::db();
$result = $db->query($query);
@ -103,13 +104,13 @@ class ModelMySQL {
* Construye la sentencia SQL a partir static::$querySelect y una vez
* construída, llama a resetQuery.
*
* @param boolean $resetQuery
* @param bool $resetQuery
* Indica si el query debe reiniciarse o no (por defecto es true).
*
* @return string
* Contiene la sentencia SQL.
*/
protected static function buildQuery($resetQuery = true) {
protected static function buildQuery(bool $resetQuery = true) : string {
if (static::$querySelect['sql_calc_found_rows'])
$sql = 'SELECT SQL_CALC_FOUND_ROWS '.join(', ', static::$querySelect['select']);
else
@ -169,7 +170,7 @@ class ModelMySQL {
* @return ModelMySQL
* Retorna un objeto de la clase actual.
*/
protected static function getInstance($elem = []) {
protected static function getInstance(array $elem = []) : ModelMySQL {
$class = get_called_class();
$instance = new $class;
@ -181,10 +182,15 @@ class ModelMySQL {
}
/**
* Devuelve los atributos a guardar de la case actual.
* Los atributos serán aquellos que seran public y
* no esten excluidos en static::$ignoresave y aquellos
* que sean private o protected pero estén en static::$forceSave.
*
* @return array
* Contiene los atributos indexados del objeto actual.
*/
protected function getVars() {
protected function getVars() : array {
$reflection = new \ReflectionClass($this);
$properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
$result = [];
@ -206,10 +212,12 @@ class ModelMySQL {
}
/**
* Devuelve el nombre de la clase actual aunque sea una clase extendida.
*
* @return string
* Devuelve el nombre de la clase actual.
*/
public static function className() {
public static function className() : string {
return strtolower(substr(strrchr(get_called_class(), '\\'), 1));
}
@ -220,7 +228,7 @@ class ModelMySQL {
*
* @return string
*/
protected static function table() {
protected static function table() : string {
if (isset(static::$table))
return static::$table;
return static::className().static::$tableSufix;
@ -310,8 +318,10 @@ class ModelMySQL {
*
* @param array $columns
* Columnas que se selecionarán en la consulta SQL.
*
* @return ModelMySQL
*/
public static function select($columns) {
public static function select(array $columns) : ModelMySQL {
$db = static::db();
$select = [];
foreach($columns as $column) {
@ -328,8 +338,10 @@ class ModelMySQL {
*
* @param array $tables
* Tablas que se selecionarán en la consulta SQL.
*
* @return ModelMySQL
*/
public static function from($tables) {
public static function from(array $tables) : ModelMySQL {
$db = static::db();
$from = [];
foreach($tables as $table) {
@ -353,11 +365,12 @@ class ModelMySQL {
* @param string $value
* (opcional) El valor el valor a comparar en la columna.
*
* @param boolean $no_quote
* @param bool $no_quote
* (opcional) Se usa cuando $value es una columna o un valor que no requiere comillas.
*
* @return ModelMySQL
*/
public static function where($column, $operator, $value=null, $no_quote = false) {
public static function where(string $column, string $operator, string $value=null, bool $no_quote = false) : ModelMySQL {
if (is_null($value)) {
$value = $operator;
$operator = '=';
@ -382,10 +395,12 @@ class ModelMySQL {
* @param array $arr
* Arreglo con todos los valores a comparar con la columna.
*
* @param boolean $in
* (opcional) Define si se usará IN o NOT IN en la sentencia SQL.
* @param bool $in
* Define si se tienen que comprobar negativa o positivamente.
*
* @return ModelMySQL
*/
public static function where_in($column, $arr, $in = true) {
public static function where_in(string $column, array $arr, bool $in = true) : ModelMySQL {
foreach($arr as $index => $value) {
$arr[$index] = static::db()->real_escape_string($value);
}
@ -412,8 +427,10 @@ class ModelMySQL {
*
* @param string $columnB
* (opcional) Columna a comparar para hacer el join.
*
* @return ModelMySQL
*/
public static function leftJoin($table, $columnA, $operator, $columnB = null) {
public static function leftJoin(string $table, string $columnA, string $operator, string $columnB = null) : ModelMySQL {
if (is_null($columnB)) {
$columnB = $operator;
$operator = '=';
@ -443,8 +460,9 @@ class ModelMySQL {
* @param string $columnB
* (opcional) Columna a comparar para hacer el join.
*
* @return ModelMySQL
*/
public static function rightJoin($table, $columnA, $operator, $columnB = null) {
public static function rightJoin(string $table, string $columnA, string $operator, string $columnB = null) : ModelMySQL {
if (is_null($columnB)) {
$columnB = $operator;
$operator = '=';
@ -472,8 +490,10 @@ class ModelMySQL {
*
* @param string $columnB
* (opcional) Columna a comparar para hacer el join.
*
* @return ModelMySQL
*/
public static function innerJoin($table, $columnA, $operator, $columnB = null) {
public static function innerJoin(string $table, string $columnA, string $operator, string $columnB = null) : ModelMySQL {
if (is_null($columnB)) {
$columnB = $operator;
$operator = '=';
@ -499,11 +519,12 @@ class ModelMySQL {
* @param string $value
* (opcional) El valor el valor a comparar en la columna.
*
* @param $no_quote
* @param bool $no_quote
* (opcional) Se usa cuando $value es una columna o un valor que no requiere comillas.
*
* @return ModelMySQL
*/
public static function and($column, $operator, $value=null, $no_quote = false) {
public static function and(string $column, string $operator, string $value=null, bool $no_quote = false) : ModelMySQL {
if (is_null($value)) {
$value = $operator;
$operator = '=';
@ -531,10 +552,12 @@ class ModelMySQL {
* @param string $value
* (opcional) El valor el valor a comparar en la columna.
*
* @param $no_quote
* @param bool $no_quote
* (opcional) Se usa cuando $value es una columna o un valor que no requiere comillas.
*
* @return ModelMySQL
*/
public static function or($column, $operator, $value=null, $no_quote = false) {
public static function or(string $column, string $operator, string $value=null, bool $no_quote = false) : ModelMySQL {
if (is_null($value)) {
$value = $operator;
$operator = '=';
@ -555,16 +578,23 @@ class ModelMySQL {
*
* @param array $arr
* Columnas por las que se agrupará.
*
* @return ModelMySQL
*/
public static function groupBy($arr) {
public static function groupBy(array $arr) : ModelMySQL {
static::$querySelect['groupBy'] = join(', ', $arr);
return new static();
}
public static function limit($initial, $final = 0) {
$initial = (int)$initial;
$final = (int)$final;
/**
* Define LIMIT en la sentencia SQL.
*
* @param int $initial
* @param int $final
*
* @return ModelMySQL
*/
public static function limit(int $initial, int $final = 0) : ModelMySQL {
if ($final==0)
static::$querySelect['limit'] = $initial;
else
@ -582,8 +612,10 @@ class ModelMySQL {
* @param string $order
* (opcional) Define si el orden será de manera ascendente (ASC),
* descendente (DESC) o aleatorio (RAND).
*
* @return ModelMySQL
*/
public static function orderBy($value, $order = 'ASC') {
public static function orderBy(string $value, string $order = 'ASC') : ModelMySQL {
if ($value == "RAND") {
static::$querySelect['orderBy'] = 'RAND()';
return new static();
@ -602,15 +634,15 @@ class ModelMySQL {
/**
* Retorna la cantidad de filas que hay en un query.
*
* @param boolean $resetQuery
* @param bool $resetQuery
* (opcional) Indica si el query debe reiniciarse o no (por defecto es true).
*
* @param boolean $useLimit
* @param bool $useLimit
* (opcional) Permite usar limit para estabecer un máximo inical y final para contar. Requiere que se haya definido antes el límite (por defecto en false).
*
* @return int
*/
public static function count($resetQuery = true, $useLimit = false) {
public static function count(bool $resetQuery = true, bool $useLimit = false) : int {
if (!$resetQuery)
$backup = [
'select' => static::$querySelect['select'],
@ -653,7 +685,7 @@ class ModelMySQL {
*
* @return int
*/
public static function found_row() {
public static function found_row() : int {
$result = static::query('SELECT FOUND_ROWS() AS quantity')->fetch_assoc();
return $result['quantity'];
}
@ -663,7 +695,7 @@ class ModelMySQL {
*
* @return ModelMySQL
*/
public static function sql_calc_found_rows() {
public static function sql_calc_found_rows() : ModelMySQL {
static::$querySelect['sql_calc_found_rows'] = true;
return new static();
}
@ -674,7 +706,7 @@ class ModelMySQL {
* @param mixed $id
* @return ModelMySQL
*/
public static function getById($id) {
public static function getById($id) : ModelMySQL {
return static::where(static::$primaryKey, $id)->getFirst();
}
@ -686,8 +718,10 @@ class ModelMySQL {
*
* @param array $in
* (opcional) Columnas en las que se va a buscar (null para buscar en todas).
*
* @return ModelMySQL
*/
public static function search($search, $in = null) {
public static function search(string $search, array $in = null) : ModelMySQL {
if ($in == null) {
$className = get_called_class();
$in = array_keys((new $className())->getVars());
@ -714,12 +748,13 @@ class ModelMySQL {
/**
* Obtener los resultados de la consulta SQL.
*
* @param boolean $resetQuery
* @param bool $resetQuery
* (opcional) Indica si el query debe reiniciarse o no (por defecto es true).
*
* @return ModelMySQL[]
* @return array
* Contiene un arreglo de instancias de la clase actual.
*/
public static function get($resetQuery = true) { // Devuelve array vacío si no encuentra nada.
public static function get(bool $resetQuery = true) : array { // Devuelve array vacío si no encuentra nada.
$sql = static::buildQuery($resetQuery);
$result = static::query($sql);
@ -735,13 +770,13 @@ class ModelMySQL {
/**
* El primer elemento de la consulta SQL.
*
* @param boolean $resetQuery
* @param bool $resetQuery
* (opcional) 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($resetQuery = true) { // Devuelve null si no encuentra nada.
public static function getFirst(bool $resetQuery = true) { // Devuelve null si no encuentra nada.
static::limit(1);
$instances = static::get($resetQuery);
return empty($instances) ? null : $instances[0];
@ -750,9 +785,10 @@ class ModelMySQL {
/**
* Obtener todos los elementos del la tabla de la instancia actual.
*
* @return ModelMySQL[]
* @return array
* Contiene un arreglo de instancias de la clase actual.
*/
public static function all() {
public static function all() : array {
$sql = 'SELECT * FROM '.static::table();
$result = static::query($sql);
@ -770,9 +806,12 @@ class ModelMySQL {
* Permite definir como nulo el valor de un atributo.
* Sólo funciona para actualizar un elemento de la BD, no para insertar.
*
* @trows \Exception
* Devolverá un error en caso de usarse en un insert.
*
* @param array $atts
*/
public function setNull($atts) {
public function setNull(array $atts) {
if (!isset($this->id))
throw new \Exception(
"\nEl método setNull sólo funciona para actualizar, no al insertar."

View File

@ -34,7 +34,7 @@ class Router {
* @param string $path
* Ruta con pseudovariables.
*
* @param callable $callback
* @param mixed $callback
* Callback que será llamado cuando la ruta configurada en $path coincida.
*
* @return array
@ -42,7 +42,7 @@ class Router {
* path - Contiene la ruta con las pseudovariables reeplazadas por expresiones regulares.
* callback - Contiene el callback en formato Namespace\Clase::Método.
*/
private static function parse($path, $callback) {
private static function parse(string $path, $callback) : array {
preg_match_all('/{(\w+)}/s', $path, $matches, PREG_PATTERN_ORDER);
$paramNames = $matches[1];
@ -69,8 +69,10 @@ class Router {
*
* Ej: Si la url del sistema está en "https://ejemplo.com/duckbrain"
* entonces la ruta base sería "/duckbrain"
*
* @return string
*/
public static function basePath() {
public static function basePath() : string {
if (defined('SITE_URL'))
return parse_url(SITE_URL, PHP_URL_PATH);
return str_replace($_SERVER['DOCUMENT_ROOT'], '/', ROOT_DIR);
@ -86,7 +88,7 @@ class Router {
* llamamos a Router::redirect('/docs'), entonces seremos
* redirigidos a "https://ejemplo.com/duckbrain/docs".
*/
public static function redirect($path) {
public static function redirect(string $path) {
header('Location: '.static::basePath().substr($path,1));
}
@ -94,14 +96,14 @@ class Router {
* Añade un middleware a la última ruta usada.
* Solo se puede usar un middleware a la vez.
*
* @param string $callback
* @param mixed $callback
*
* @return static
* @return Router
* Devuelve un enlace estático.
*/
public static function middleware($callback){
public static function middleware($callback) : Router{
if (!isset(static::$last))
return;
return new static();
$method = static::$last[0];
$index = static::$last[1];
@ -116,15 +118,15 @@ class Router {
}
/*
* @return object
* @return Neuron
* Devuelve un objeto que contiene los atributos:
* post - Donde se encuentran los valores enviados por $_POST.
* get - Donde se encuentran los valores enviados por $_GET.
* json - Donde se encuentran los valores JSON enviados en el body.
*
*/
private static function getReq() {
$req = (object) '';
private static function getReq() : Neuron {
$req = new Neuron();
$req->get = new Neuron($_GET);
$req->post = new Neuron($_POST);
$req->json = new Neuron(static::get_json());
@ -137,7 +139,7 @@ class Router {
* @return object
* Devuelve un objeto con los datos recibidos en JSON.
*/
private static function get_json() {
private static function get_json() : object {
$contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : '';
if ($contentType === "application/json") {
return json_decode(trim(file_get_contents("php://input")));
@ -151,13 +153,13 @@ class Router {
* @param string $path
* Ruta con pseudovariables.
*
* @param callable $callback
* @param mixed $callback
* Callback que será llamado cuando la ruta configurada en $path coincida.
*
* @return static
* @return Router
* Devuelve un enlace estático.
*/
public static function get($path, $callback) {
public static function get(string $path, $callback) {
static::$get[] = static::parse($path, $callback);
static::$last = ['get', count(static::$get)-1];
return new static();
@ -169,13 +171,13 @@ class Router {
* @param string $path
* Ruta con pseudovariables.
*
* @param callable $callback
* @param mixed $callback
* Callback que será llamado cuando la ruta configurada en $path coincida.
*
* @return static
* @return Router
* Devuelve un enlace estático.
*/
public static function post($path, $callback) {
public static function post(string $path, $callback) : Router {
static::$post[] = static::parse($path, $callback);
static::$last = ['post', count(static::$post)-1];
return new static();
@ -187,14 +189,14 @@ class Router {
* @param string $path
* Ruta con pseudovariables.
*
* @param callable $callback
* @param mixed $callback
* Callback que será llamado cuando la ruta configurada en $path coincida.
*
* @return static
* @return Router
* Devuelve un enlace estático
*/
public static function put($path, $callback) {
public static function put(string $path, $callback) : Router {
static::$put[] = static::parse($path, $callback);
static::$last = ['put', count(static::$put)-1];
return new static();
@ -212,7 +214,7 @@ class Router {
* @return static
* Devuelve un enlace estático
*/
public static function delete($path, $callback) {
public static function delete(string $path, $callback) : Router {
static::$delete[] = static::parse($path, $callback);
static::$last = ['delete', count(static::$delete)-1];
return new static();
@ -220,8 +222,10 @@ class Router {
/*
* Devuelve la ruta actual.
*
* @return string
*/
public static function currentPath() {
public static function currentPath() : string {
return preg_replace('/'.preg_quote(static::basePath(), '/').'/',
'/', strtok($_SERVER['REQUEST_URI'], '?'), 1);
}

View File

@ -25,7 +25,7 @@ class View {
* @param string $viewPath
* (opcional) Ruta donde se encuentra la vista. En caso de que la vista no se encuentre en esa ruta, se usará la ruta por defecto "src/Views/".
*/
public static function render($viewName, $params = [], $viewPath = null) {
public static function render(string $viewName, array $params = [], string $viewPath = null) {
$view = new Neuron($params);
unset($params);