Construya un mejor enrutador

En este episodio, construiremos un enrutador mejor que pueda manejar y responder a cualquier tipo de solicitud de formulario. Sin embargo, debido a que los formularios solo admiten GET y POST de forma nativa, necesitaremos usar un campo de entrada oculto para falsificar el tipo de solicitud.

Que aprenderemos

  • Request Methods
  • Request Type Spoofing
  • Routing

Cambiar nombre a Core/router.php a Core/Router.php

Ya que vamos a crear una clase en este archivo! Tenemos que preparar los métodos que vamos a poder manejar así:

<?php 

class Router {
    public function get(){

    }

    public function post(){
        
    }

    public function delete(){
        
    }

    public function patch(){
        
    }

    public function put(){
        
    }
}

Código en Core/Router.php

<?php 

namespace Core;

class Router {
    protected $routes = [];

    public function add($method, $uri, $controller){
        $this->routes[] = compact('method', 'uri', 'controller');
    }

    public function get($uri, $controller){
        $this->add('GET', $uri, $controller);
    }

    public function post($uri, $controller){
        $this->add('POST', $uri, $controller);
    }

    public function delete($uri, $controller){
        $this->add('DELETE', $uri, $controller);
    }

    public function patch($uri, $controller){
        $this->add('PATCH', $uri, $controller);
    }

    public function put($uri, $controller){
        $this->add('PUT', $uri, $controller);
    }


    public function route($uri, $method){

        foreach ($this->routes as $route) {
            if ($route['uri'] === $uri && $route['method'] === strtoupper($method) ) {
                return require base_path($route['controller']);
            }
        }

        $this->abort();
    }

    protected function abort($code = 404){
        http_response_code($code);
        require base_path("views/{$code}.php");
        die();
    }
}

Código en public/index.php

<?php 
const BASE_PATH = __DIR__ . '/../';

require BASE_PATH . 'Core/functions.php';
require base_path('Core/display_errors.php');

spl_autoload_register(function ($class){
    // dd($class);
    // dd(base_path($class . '.php'));
    // require base_path("Core/" . $class . '.php');
    $class = str_replace('\\', DIRECTORY_SEPARATOR, $class);
    // $result = "{$class}.php";
    // dd($result);
    require base_path("{$class}.php");
});

$router = new \Core\Router();
$routes = require base_path('routes.php');
$uri = parse_url($_SERVER['REQUEST_URI'])['path'];
$method = $_POST['_method'] ?? $_SERVER['REQUEST_METHOD'];

$router->route($uri, $method);

Código en routes.php

<?php 

$router->get('/', 'controllers/index.php');
$router->get('/about', 'controllers/about.php');
$router->get('/contact', 'controllers/contact.php');

$router->get('/notes', 'controllers/notes/index.php');
$router->get('/note', 'controllers/notes/show.php');
$router->get('/notes/create', 'controllers/notes/create.php');
$router->delete('/note', 'controllers/notes/destroy.php');

Código en views/notes/show.view.php

<!-- html head -->
<?php require base_path('views/partials/head.php') ?>
<!-- Navegación -->
<?php require base_path('views/partials/nav.php') ?>
<!-- Encabezado (Banner)-->
<?php require base_path('views/partials/banner.php') ?>

<!-- Contenido -->
<main>
    <div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">

        <p class="mb-6">
            <a href="/notes" class="text-blue-500 underline">Regresar...</a>
        </p>

        <p>
            <?= htmlspecialchars($note['body']) ?>
        </p>

        <form class="mt-6" method="POST">
            <input type="hidden" name="_method" value="DELETE"> 
            <input type="hidden" name="id" value="<?= $note['id'] ?>">
            <button class="text-sm text-red-500">Eliminar</button>
        </form>

    </div>
</main>

<?php require base_path('views/partials/footer.php') ?>

Código en Core/functions.php

<?php 

use Core\Response;

// función Dump and Die
function dd($value) {
    echo "<pre>";
    var_dump($value);
    echo "</pre>"; 
    die(); 
}

// Me regresa true or false
function urlIs($value){
    return $_SERVER['REQUEST_URI'] === $value;
}

// Abort
function abort($code = 404){
    http_response_code($code);
    require base_path("views/{$code}.php");
    die();
}

// check si el usuario esta autorizado
function authorize($condition, $status = Response::FORBIDDEN){
    if (! $condition) {
        abort($status); 
    }
}

function base_path($path){
    return BASE_PATH . $path;
}

function view($path, $attributes = []){
    extract($attributes);
    require base_path('views/' . $path);
}

Compact

Podemos reducir este método:

public function add($method, $uri, $controller){
	$this->routes[] =[
		'uri' => $uri,
		'controller' => $controller,
		'method' => $method
	];
}

A compactarlo con la función de php compact así:

public function add($method, $uri, $controller){
	$this->routes[] = compact('method', 'uri', 'controller');
}

compact(array|string $var_name, array|string|null ...$var_names): array $var_name: compact() takes a variable number of parameters. Each parameter can be either a string containing the name of the variable, or an array of variable names. The array can contain other arrays of variable names inside it; compact() handles it recursively. Create array containing variables and their values Creates an array containing variables and their values

Quedo pendiente lo de DELETE y Crear Nota! Listo!