From 9539b432124f3e5e04d4b72d9cbe8ddd2353bb0d Mon Sep 17 00:00:00 2001 From: kj Date: Sat, 7 Mar 2020 23:37:19 -0400 Subject: [PATCH] First commit. --- .htaccess | 8 + config.php | 12 ++ index.php | 24 +++ readme.md | 7 + src/Libs/Database.php | 19 +++ src/Libs/ModelMySQL.php | 370 ++++++++++++++++++++++++++++++++++++++++ src/Libs/Params.php | 17 ++ src/Libs/Router.php | 145 ++++++++++++++++ src/Libs/View.php | 13 ++ src/init.php | 28 +++ 10 files changed, 643 insertions(+) create mode 100644 .htaccess create mode 100644 config.php create mode 100644 index.php create mode 100644 readme.md create mode 100644 src/Libs/Database.php create mode 100644 src/Libs/ModelMySQL.php create mode 100644 src/Libs/Params.php create mode 100644 src/Libs/Router.php create mode 100644 src/Libs/View.php create mode 100644 src/init.php diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..852b209 --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ + + RewriteEngine On + + # Handle Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/config.php b/config.php new file mode 100644 index 0000000..28ae170 --- /dev/null +++ b/config.php @@ -0,0 +1,12 @@ + + + diff --git a/index.php b/index.php new file mode 100644 index 0000000..5d91b3a --- /dev/null +++ b/index.php @@ -0,0 +1,24 @@ + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..3fdf2fd --- /dev/null +++ b/readme.md @@ -0,0 +1,7 @@ +# DuckBrain - PHP Microframework + +Este microframework PHP tiene el objetivo de presentar un framework sencillo y potente que sea válido para todo proyecto, pero sin inmiscuírse demasiado, ni depender de cosas que agranden innecesariamente proyectos pequeños. + +De igual modo, lo ideal sería mantener el código sencillo; lo suficiente como para que cualquier novato que sepa POO y PHP pueda leerlo rápido, entenderlo y modificarlo a gusto. + +Por este motivo también he decidido desligarlo en lo posible de composer o cualquier cosa similar, ya que no pocos programadores en etapa de aprendizaje al encontrarse con frameworks más complicados o con herramientas como composer, terminan trabajando con cosas que no comprenden ni pueden arreglar por si mismos en caso de fallos. diff --git a/src/Libs/Database.php b/src/Libs/Database.php new file mode 100644 index 0000000..f55f1bb --- /dev/null +++ b/src/Libs/Database.php @@ -0,0 +1,19 @@ +connect_errno) { + exit('No se ha podido conectar a la base de datos.'); + } + } + return self::$db; + } +} +?> diff --git a/src/Libs/ModelMySQL.php b/src/Libs/ModelMySQL.php new file mode 100644 index 0000000..2961d7d --- /dev/null +++ b/src/Libs/ModelMySQL.php @@ -0,0 +1,370 @@ + '*', + 'where' => '', + 'AndOr' => '', + 'orderBy'=>'', + 'groupBy'=>'', + 'limit' => '', + ]; + + private static function db(){ + if (is_null(self::$db)) + self::$db = Database::getConnection(); + + return self::$db; + } + + private static function query($query){ + $db = self::db(); + + $result = $db->query($query); + if ($db->errno){ + echo 'Fallo al consultar la base de datos.
+ Errno: ' . addslashes ($db->errno).'
+ Error: ' . addslashes ($db->error).'
'.$query; + exit(); + } + + return $result; + } + + private static function resetQuery(){ + self::$querySelect = [ + 'select' => '*', + 'where' => '', + 'AndOr' => '', + 'orderBy'=>'', + 'groupBy'=>'', + 'limit' => '', + ]; + } + + private static function buildQuery(){ + $sql = 'SELECT '.self::$querySelect['select'].' FROM '.self::table(); + + if (self::$querySelect['where'] != ''){ + $sql .= ' WHERE '.self::$querySelect['where']; + + if (self::$querySelect['AndOr'] != ''){ + $sql .= self::$querySelect['AndOr']; + } + } + + if (self::$querySelect['groupBy'] != ''){ + $sql .= ' GROUP BY '.self::$querySelect['groupBy']; + } + + if (self::$querySelect['orderBy'] != ''){ + $sql .= ' ORDER BY '.self::$querySelect['orderBy']; + } + + if (self::$querySelect['limit'] != ''){ + $sql .= ' LIMIT '.self::$querySelect['limit']; + } + + self::resetQuery(); + + return $sql; + } + + + public function getInstance($elem = []){ + $class = get_called_class(); + $instace = new $class; + + foreach ($elem as $key => $value){ + $instace->$key = $value; + } + + return $instace; + } + + + private function getVars(){ // Source: https://stackoverflow.com/questions/10009015/show-all-public-attributes-name-and-value-of-an-object + $get_vars_proxy = create_function('$obj', 'return get_object_vars($obj);'); + $result = $get_vars_proxy($this); + foreach ($this->ignoreSave as $del){ + unset($result[$del]); + } + + foreach ($this->forceSave as $value){ + $result[$value] = $this->$value; + } + + return $result; + } + + + public static function className(){ + return strtolower(substr(strrchr(get_called_class(), '\\'), 1)); + } + + + private static function table(){ + if (isset(self::$table)) + return self::$table; + return self::className().self::$tableSufix; + } + + + private function update(){ + $atts = $this->getVars(); + + foreach ($atts as $key => $value){ + $value = self::db()->real_escape_string($value); + $set[]="$key='$value'"; + } + + $table = self::table(); + $pk = $this->primaryKey; + $pkv = $this->$pk; + $sql = "UPDATE $table SET ".join(', ', $set)." WHERE $pk='$pkv'"; + self::query($sql); + } + + + private function add(){ + $db = self::db(); + $atts = $this->getVars(); + + foreach ($atts as $key => $value){ + $into[] = "`$key`"; + $values[] = "'".$db->real_escape_string($value)."'"; + } + + $table = self::table(); + $sql = "INSERT INTO $table (".join(', ', $into).") VALUES (".join(', ', $values).")"; + self::query($sql); + + $pk = $this->primaryKey; + $this->$pk = $db->insert_id; + } + + + public function save(){ + $pk = $this->primaryKey; + if (isset($this->$pk)) + $this->update(); + else + $this->add(); + } + + + public function delete(){ + $atts = $this->getVars(); + + foreach ($atts as $key => $value){ + $value = self::db()->real_escape_string($value); + $set[]="$key='$value'"; + } + + $table = self::table(); + $pk = $this->primaryKey; + $pkv = $this->$pk; + $sql = "DELETE FROM $table WHERE $pk='$pkv'"; + self::query($sql); + } + + + public static function select($value){ + $db = self::db(); + $select = []; + foreach($value as $elem){ + $select[] = $db->real_escape_string($elem); + } + + self::$querySelect['select'] = join(', ', $select); + + return new static(); + } + + /* + * Sintaxis permitidas: + * - Class::where(columna, operador, valor) + * - Class::where(columna, valor) // Operador por defecto "=" + */ + + public static function where($column, $operator, $value=null){ + if (is_null($value)){ + $value = $operator; + $operator = '='; + } + + $value = self::db()->real_escape_string($value); + + self::$querySelect['where'] = "$column$operator'$value'"; + + return new static(); + } + + + public static function where_in($column,$arr, $in = true){ + foreach($arr as $index => $value){ + $arr[$index] = self::db()->real_escape_string($value); + } + + if ($in) + self::$querySelect['where'] = "$column IN (".join(', ',$arr).")"; + else + self::$querySelect['where'] = "$column NOT IN (".join(', ',$arr).")"; + + return new static(); + } + + + public static function and($column, $operator, $value=null){ + if (is_null($value)){ + $value = $operator; + $operator = '='; + } + + $value = self::db()->real_escape_string($value); + + self::$querySelect['AndOr'] = " AND $column$operator'$value'"; + + return new static(); + } + + + public static function or($column, $operator, $value=null){ + if (is_null($value)){ + $value = $operator; + $operator = '='; + } + + $value = self::db()->real_escape_string($value); + + self::$querySelect['AndOr'] = " OR $column$operator'$value'"; + + return new static(); + } + + public static function groupBy($arr){ + self::$querySelect['groupBy'] = join(', ', $arr); + return new static(); + } + + public static function limit($initial, $final = 0){ + $initial = (int)$initial; + $final = (int)$final; + + if ($final==0) + self::$querySelect['limit'] = $initial; + else + self::$querySelect['limit'] = $initial.', '.$final; + + return new static(); + } + + + public static function orderBy($value, $order = 'ASC'){ + if ($value == "RAND"){ + self::$querySelect['orderBy'] = 'RAND()'; + return new static(); + } + + $value = self::db()->real_escape_string($value); + + if (!(strtoupper($order) == 'ASC' || strtoupper($order) == 'DESC')) + $order = 'ASC'; + + self::$querySelect['orderBy'] = $value.' '.$order; + + return new static(); + } + + + public static function count(){ + self::$querySelect['select'] = 'count(*) as quantity'; + $sql = self::buildQuery(); + $result = self::query($sql)->fetch_assoc(); + return $result['quantity']; + } + + + public static function getById($id){ + return self::where('id', $id)->getFirst(); + } + + + public static function search($search, $in = null){ + $className = get_called_class(); + $objAtts = array_keys((new $className())->getVars()); + + if ($in == null){ + $in = $objAtts; + } + + $db = self::db(); + + $search = $db->real_escape_string($search); + + $where = []; + + foreach($in as $row){ + if(in_array($row, $objAtts)) + $where[] = "$row LIKE '%$search%'"; + } + + if (self::$querySelect['where']=='') + self::$querySelect['where'] = join($where, ' OR '); + else + self::$querySelect['where'] = self::$querySelect['where'] .' AND ('.join($where, ' OR ').')'; + + return new static(); + } + + + public static function get(){ // Devuelve array vacío si no encuentra nada + $sql = self::buildQuery(); + $result = self::query($sql); + + $instaces = []; + + while ($row = $result->fetch_assoc()){ + $instaces[] = self::getInstance($row); + } + + return $instaces; + } + + + public static function getFirst(){ // Devuelve null si no encuentra nada + self::limit(1); + $instaces = self::get(); + return empty($instaces) ? null : $instaces[0]; + } + + + public static function all(){ + $sql = 'SELECT * FROM '.self::table(); + + $result = self::query($sql); + + $instaces = []; + + while ($row = $result->fetch_assoc()){ + $instaces[] = self::getInstance($row); + } + + return $instaces; + } +} +?> diff --git a/src/Libs/Params.php b/src/Libs/Params.php new file mode 100644 index 0000000..bc14631 --- /dev/null +++ b/src/Libs/Params.php @@ -0,0 +1,17 @@ + $value){ + $this->$index = $value; + } + } + + public function __get($index){ + return (isset($this->$index) && $this->$index != '') ? urldecode($this->$index) : null; + } +} + +?> diff --git a/src/Libs/Router.php b/src/Libs/Router.php new file mode 100644 index 0000000..d7c3cb6 --- /dev/null +++ b/src/Libs/Router.php @@ -0,0 +1,145 @@ + $path, + 'callback' => $callback + ]; + } + + public static function baseURI(){ + return str_replace($_SERVER['DOCUMENT_ROOT'],'/', ROOT_DIR); + } + + public static function redirect($uri){ + header('Location: '.self::baseURI().substr($uri,1)); + } + + public static function middleware($middleware){ // Solo soporta un middleware a la vez + if (!isset(self::$last)) return; + + $method = self::$last[0]; + $index = self::$last[1]; + + self::$$method[$index]['middleware'] = 'Middlewares\\'.$middleware; + } + + public static function get($path, $callback){ + self::$get[] = self::parse($path, $callback); + self::$last = ['get', count(self::$get)-1]; + return new static(); + } + + private static function params(){ + $args = (object) ''; + $args->get = new Params($_GET); + $args->post = new Params($_POST); + $args->json = new Params(self::get_json()); + return $args; + } + + private static function get_json(){ + $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : ''; + if ($contentType === "application/json"){ + return json_decode(trim(file_get_contents("php://input"))); + } + return (object) ''; + } + + public static function post($path, $callback){ + self::$post[] = self::parse($path, $callback); + self::$last = ['post', count(self::$post)-1]; + return new static(); + } + + public static function put($path, $callback){ + self::$put[] = self::parse($path, $callback); + self::$last = ['put', count(self::$put)-1]; + return new static(); + } + + public static function delete($path, $callback){ + self::$delete[] = self::parse($path, $callback); + self::$last = ['delete', count(self::$put)-1]; + return new static(); + } + + public static function apply(){ + $uri = preg_replace('/'.preg_quote(self::baseURI(), '/').'/', + '/', strtok($_SERVER['REQUEST_URI'], '?'), 1); + $routers = []; + switch ($_SERVER['REQUEST_METHOD']){ + case 'POST': + $routers = self::$post; + break; + case 'PUT': + $routers = self::$put; + break; + case 'DELETE': + $routers = self::$delete; + break; + default: + $routers = self::$get; + break; + } + + foreach ($routers as $router){ + if (preg_match_all('/^'.$router['path'].'\/?$/si',$uri, $matches)){ + unset($matches[0]); + $args = self::params(); + + if (isset($matches[1])){ + $params = []; + foreach ($matches as $match){ + if (!empty($match)) + $params[] = "$match[0]"; + } + + if (isset($router['middleware'])){ + $middleware = explode('::',$router['middleware']); + $data = call_user_func_array($middleware, [$router['callback'], $args, $params]); + }else + $params[] = $args; + $data = call_user_func_array($router['callback'], $params); + }else{ + if (isset($router['middleware'])){ + $middleware = explode('::',$router['middleware']); + $data = call_user_func_array($middleware, [$router['callback'], $args]); + }else + $data = call_user_func_array($router['callback'], [$args]); + } + + if (isset($data)){ + header('Content-Type: application/json'); + print(json_encode($data)); + } + + return; + } + } + header("HTTP/1.0 404 Not Found"); + echo '

Error 404 - Página no encontrada

'; + } +} + diff --git a/src/Libs/View.php b/src/Libs/View.php new file mode 100644 index 0000000..509e6bc --- /dev/null +++ b/src/Libs/View.php @@ -0,0 +1,13 @@ + diff --git a/src/init.php b/src/init.php new file mode 100644 index 0000000..918cc3e --- /dev/null +++ b/src/init.php @@ -0,0 +1,28 @@ +connect_errno){ + exit('No se ha podido conectar a la base de datos.'); +} + +// Incluir clases +spl_autoload_register(function ($className) { + $fp = str_replace('\\','/',$className); + $name = basename($fp); + $dir = dirname($fp); + $file = ROOT_DIR.'/src/'.$dir.'/'.$name.'.php'; + if (file_exists($file)) { + require_once $file; + return; + } +}); + +// Incluir routers +$routers = glob(ROOT_DIR.'/src/Routers/*.php'); + +foreach($routers as $file){ + require_once($file); +} + +\Libs\Router::apply(); +?>