49. Crear un simple enrutador con PHP

En el capítulo pasado habíamos logrado que nuestra aplicación tuviera un único punto de acceso, es decir, a que no importa lo que coloquemos luego de la URL principal, siempre se abrirá el mismo archivo, el archivo index.php. incluido dentro de la carpeta public. Nuestro archivo index.php es un documento HTML que tiene una etiqueta <h1></h1> cuyo valor es Inicio punto de acceso.

index.php

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>Único punto de acceso</h1>
</body>
</html>

 

Lo siguiente que debemos hacer es que desde este archivo analizar la URL desde la cual estamos haciendo la petición, y dependiendo del valor de dicha URL deberíamos llamar a uno u otro controlador. Este proceso en el cual analizamos la URL y dependiendo de dicha URL llamamos a uno u otro controlador se le conoce como enrutamiento, y cabe resaltar que no existe una única forma de generar este enrutamiento, cada programador puede tener su propio estilo para este enrutamiento. En este curso vamos a ver un enrutamiento inspirado en el de Laravel, que es un framework PHP.

Generar el enrutamiento

Para generar el enrutamiento vamos a utilizar la programación orientada a objetos (OOP). Vamos a crear una clase especializada y que sea esa clase la que se encargue de todo este proceso de enrutar.

Cabe recalcar que hay que estar familiarizado con la programación orientada a objetos. 

Clase encargada del enrutamiento

Vamos a crear una clase que va a ser la encargada del enrutamiento, para lo cual vamos a ir a nuestro directorio y vamos a crear una nueva carpeta en la raíz, denominada lib de librería, y desde aquí crear un nuevo archivo al que le vamos a dar el nombre Route.php. Dentro de este archivo vamos a crear la clase que se va a encargar de hacer el enrutamiento.

Tipos de peticiones

Nosotros desde nuestra aplicación vamos a poder hacer dos tipos de peticiones, de tipo GET y de tipo POST. Cuando definamos estas rutas tenemos que considerar a ambos tipos de peticiones, no solo las de tipo GET.

Esquema de nuestra app

El esquema de nuestra app hasta ahora es el siguiente:

  • app
  • lib
    • Route.php (tendrá una clase)
  • public
    • css
    • img
    • js
    • .htaccess
    • index.php (archivo principal)
  • routes
    • web.php (contiene las diferentes rutas)
  • .htaccess
  • autoload (autocargador)

Veamos la sintaxis de los archivos nuevos

public/index.php (archivo principal)

<?php

// Carga el archivo autoload.php que carga automáticamente archivos
// Ver capítulo autocargador para entender como funciona nuestro autoload
require_once '../autoload.php';

require_once('../routes/web.php');

 

routes/web.php (vamos agregando o modificando rutas)

<?php

use Lib\Route;

Route::get('/', function(){
  echo 'Hola desde la página principal';
});

Route::get('/contact', function(){
  echo 'Hola desde la página de contacto';
});

Route::get('/about', function(){
  echo 'Hola desde la página de acerca de';
});

 

autoload.php (se trata de un autocargador, que vimos en anteriores capítulos)

<?php

spl_autoload_register(function($clase){
  $ruta = '../' . str_replace("\\", "/", $clase) . ".php";

  if(file_exists($ruta)){
    require_once($ruta);
  } else {
    die("No se pudo cargar la clase $clase");
  }
});

 

lib/Route.php (archivo que contiene la clase Route)

<?php

namespace Lib;

class Route
{
  private static $routes = [];

  // Método encargado de agregar rutas GET
  public static function get($uri, $callback){
    self::$routes['GET'][$uri] = $callback;
  }

  // Método encargado de agregar rutas POST
  public static function post($uri, $callback){
    self::$routes['POST'][$uri] = $callback;
  }
}

 

Desde el archivo web.php iremos agregando o modificando rutas, y desde el archivo index.php sólamente colocaremos importaciones, definiremos alguna que otra variable de configuración... 

Lo siguiente que vamos a hacer es ver como conforme vayamos ingresando a diferentes rutas, se nos muestren los mensajes que hemos definido dentro de la clase Route, para ello vamos a definir dentro de esta clase un nuevo método de tipo estatic igualmente denominado dispatch(){}; Con este método lo que queremos hacer es recuperar la URI que el usuario ha escrito.

La sintaxis de este método dentro de la clase Route es la siguiente.

dispatch()

  // Método para recuperar la URI
  public static function dispatch() {
    $uri = $_SERVER['REQUEST_URI'];

    echo $uri;
  }
 

 

Posteriormente tenemos que ir al archivo routes/web.php y llamar al método

routes/web.php (método dispatch())

Route::dispatch();

 

Lo que nos va a retornar ahora es la URI que se determina de la siguiente manera, primero muestra cual es del dominio, en nuestro caso es localhost, y todo lo que viene después de localhost corresponde a la URI. El problema es que la URI muestra todo el contenido de carpetas y subcarpetas, y lo que queremos es que únicamente nos muestre la carpeta final, para ello lo que vamos a hacer es reemplazar todo ello con un dominio local, que en nuestro caso le vamos a dar el nombre mvc.test. Llegados a este punto vamos a hacer algunas modificaciones en algunos archivos de Windows.

Modificaciones en el archivo hosts

Para ello buscamos el bloc de notas y lo abrimos como administrador, y seguimos la siguiente ruta

    • C > Windows > System 32 > drivers > etc > hosts (archivo)

y hacemos clic donde dice Todos los archivos, y abrimos el archivo el archivo hosts. Estando aquí veremos nombres de dominios, lo que vamos a hacer es agregar un nuevo nombre de dominio

127.0.0.1 mvc.test

el cual pondremos al final del archivo. Es importante utilizar la extensión .text para no provocar conflicto.

Avisar a Apache abriendo el archivo httpd-vhosts.conf

Lo siguiente es avisarle a Apache que cada vez que escribamos mvc.test nos abra el proyecto localhost/mvc/public, para ello abrimos el archivo siguiendo la siguiente ruta

  • C > xampp > apache > conf > extra > httpd-vhosts.conf

Y vamos a escribir al final la siguiente sintaxis

<VirtualHost *:80>
    DocumentRoot "C:/xampp/htdocs/mvc/public/"
    ServerName mvc.test
</VirtualHost>

Podemos copiar ejemplos que vienen comentados y eliminar el resto de parámetros, quedándonos únicamente con los del ejm de arriba. Una vez hechos todos los cambios tenemos que reiniciar Apache para que la nueva configuración se ejecute.

Qué tipo de petición hemos hecho

Lo próximo que nos gustaría saber es que tipo de petición hemos hecho, si es de tipo GET o de tipo POST. Para ello en nuestra clase Route vamos a modificar el método dispatch() con la siguiente sintaxis.

  // Método para recuperar la URI y el método
  public static function dispatch() {
    $uri = $_SERVER['REQUEST_URI'];
    $uri = trim($uri, "/");

    // Variable que nos mostrará el método que hemos utilizado
    $method = $_SERVER['REQUEST_METHOD'];

    echo $uri;
    echo "<br />";
    echo $method;
  }
 

 

Buscar si existe una ruta definida

Lo próximo que debemos hacer es buscar una ruta con su respectivo método que hayamos definido en la clase, para ello vamos a volver a modificar el método dispatch(). Os dejamos el archivo completo Route.php con la clase para que se familiaricen con el código

lib/Route.php

<?php

namespace Lib;

class Route
{
  private static $routes = [];

  // Método encargado de agregar rutas GET
  public static function get($uri, $callback){
    $uri = trim($uri, "/");
    self::$routes['GET'][$uri] = $callback;
  }

  // Método encargado de agregar rutas POST
  public static function post($uri, $callback){
    $uri = trim($uri, "/");
    self::$routes['POST'][$uri] = $callback;
  }
 
  // Método para recuperar la URI y el método
  public static function dispatch() {
    $uri = $_SERVER['REQUEST_URI'];
    $uri = trim($uri, "/");

    // Variable que nos mostrará el método que hemos utilizado
    $method = $_SERVER['REQUEST_METHOD'];

    foreach(self::$routes[$method] as $route => $callback){
      if($route == $uri){
        $callback();
        return;
      }
    }
    echo "404 Not Found";
  }
}

 

En el próximo capítulo veremos la forma de pasarle parámetros por nuestras rutas.