First commit.

This commit is contained in:
kj 2020-03-07 23:37:19 -04:00
commit 9539b43212
10 changed files with 643 additions and 0 deletions

8
.htaccess Normal file
View File

@ -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>

12
config.php Normal file
View File

@ -0,0 +1,12 @@
<?php
define('dbhost', 'localhost');
define('dbname', '');
define('dbuser', '');
define('dbpass', '');
define('ROOT_DIR', __DIR__);
?>

24
index.php Normal file
View File

@ -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();
?>

7
readme.md Normal file
View File

@ -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.

19
src/Libs/Database.php Normal file
View File

@ -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;
}
}
?>

370
src/Libs/ModelMySQL.php Normal file
View File

@ -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;
}
}
?>

17
src/Libs/Params.php Normal file
View File

@ -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;
}
}
?>

145
src/Libs/Router.php Normal file
View File

@ -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>';
}
}

13
src/Libs/View.php Normal file
View File

@ -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');
}
}
?>

28
src/init.php Normal file
View File

@ -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();
?>