kj
4 years ago
commit
9539b43212
10 changed files with 643 additions and 0 deletions
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
<IfModule mod_rewrite.c> |
||||
RewriteEngine On |
||||
|
||||
# Handle Front Controller... |
||||
RewriteCond %{REQUEST_FILENAME} !-d |
||||
RewriteCond %{REQUEST_FILENAME} !-f |
||||
RewriteRule ^ index.php [L] |
||||
</IfModule> |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
<?php |
||||
|
||||
define('dbhost', 'localhost'); |
||||
define('dbname', ''); |
||||
define('dbuser', ''); |
||||
define('dbpass', ''); |
||||
|
||||
|
||||
define('ROOT_DIR', __DIR__); |
||||
?> |
||||
|
||||
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
<?php |
||||
require_once('config.php'); |
||||
|
||||
// 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(); |
||||
?> |
@ -0,0 +1,7 @@
@@ -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. |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
<?php |
||||
namespace Libs; |
||||
|
||||
class Database { |
||||
static private $db; |
||||
|
||||
private function __construct() {} |
||||
|
||||
static public function getConnection() { |
||||
if (!isset(self::$db)) { |
||||
self::$db = new \mysqli(dbhost, dbuser, dbpass, dbname); |
||||
if (self::$db->connect_errno) { |
||||
exit('No se ha podido conectar a la base de datos.'); |
||||
} |
||||
} |
||||
return self::$db; |
||||
} |
||||
} |
||||
?> |
@ -0,0 +1,370 @@
@@ -0,0 +1,370 @@
|
||||
<?php |
||||
|
||||
namespace Libs; |
||||
|
||||
use Libs\Database; |
||||
|
||||
class ModelMySQL { |
||||
|
||||
public $id; |
||||
|
||||
protected $primaryKey = 'id'; |
||||
protected $ignoreSave = ['id']; |
||||
protected $forceSave = []; |
||||
|
||||
static protected $table; |
||||
static protected $tableSufix = 's'; |
||||
static protected $db; |
||||
static protected $querySelect = [ |
||||
'select' => '*', |
||||
'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.<br> |
||||
Errno: ' . addslashes ($db->errno).'<br> |
||||
Error: ' . addslashes ($db->error).'<br>'.$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; |
||||
} |
||||
} |
||||
?> |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
<?php |
||||
|
||||
namespace Libs; |
||||
|
||||
class Params { |
||||
public function __construct($args){ |
||||
foreach($args as $index => $value){ |
||||
$this->$index = $value; |
||||
} |
||||
} |
||||
|
||||
public function __get($index){ |
||||
return (isset($this->$index) && $this->$index != '') ? urldecode($this->$index) : null; |
||||
} |
||||
} |
||||
|
||||
?> |
@ -0,0 +1,145 @@
@@ -0,0 +1,145 @@
|
||||
<?php |
||||
namespace Libs; |
||||
|
||||
use Libs\Request; |
||||
|
||||
class Router{ |
||||
private static $get = []; |
||||
private static $post = []; |
||||
private static $put = []; |
||||
private static $delete = []; |
||||
private static $last; |
||||
|
||||
private function __construct(){} |
||||
|
||||
private static function parse($path, $callback){ |
||||
$path = preg_quote($path, '/'); |
||||
$path = preg_replace( |
||||
['/\\\{[\w-]+\\\}/s'], |
||||
['([^\/]+)'], |
||||
$path); |
||||
|
||||
if (!is_callable($callback)) { |
||||
$callback = 'Controllers\\'.$callback; |
||||
} |
||||
return [ |
||||
'path'=> $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 '<h2 style="text-align: center;margin: 25px 0px;">Error 404 - Página no encontrada</h2>'; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
<?php |
||||
namespace Libs; |
||||
|
||||
defined('ROOT_DIR') || die('8)'); |
||||
|
||||
class View { |
||||
public static function render($viewName, $params = array()){ |
||||
$view = (object) $params; |
||||
unset($params); |
||||
include(ROOT_DIR.'src/Views/'.$viewName.'.php'); |
||||
} |
||||
} |
||||
?> |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
<?php |
||||
$db = new mysqli(dbhost, dbuser, dbpass, dbname); |
||||
|
||||
if ($db->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(); |
||||
?> |
Loading…
Reference in new issue