Creando nuestra primera ruta, controladores y configurando nuestras URLs en Laravel

Video thumbnail

Una vez que tengas tu Laravel Herd y proyecto creado, quiero presentar un Hola Mundo en Laravel, para que entienda los conceptos claves del framework y puedas ver algo por pantalla; comencemos definiendo los conceptos claves.

Las vistas forman parte de nuestro MVC y es la capa de presentación, de mostrar el contenido ya generado a nuestro usuario; esto es usualmente una página en HTML, pero puede ser un documento como PDF, una imagen, un video, etc; pasando por alto las referencias a documentos y similares, que serían casos especiales.

Las vistas en Laravel no son más que archivos PHPs que el framework traduce a una página HTML que es la presentada al usuario final mediante el navegador que es el que realiza la consulta inicialmente, tal cual vimos anteriormente con el caso de las rutas.

En Laravel, las vistas son especiales ya que, usualmente no son vistas PHPs comunes, si no, tienen un motor de plantilla que no es más que un mecanismo que nos permite hacer lo mismo que hacemos en PHP (imprimir, valores, llamar a funciones, mezclar PHP con HTML, etc) pero de una manera más limpia, más mantenible y más sencilla que usar directamente PHP; para poder usar el motor de plantillas, tenemos que agregar la extensión .blade antes de colocar la de .php; por ejemplo:

welcome.blade.php

Si no quisiéramos emplear el motor de blade:

welcome.php

Simplemente removemos el .blade del nombre.

Usualmente siempre usamos blade, ya que no hay una razón para no emplearlo.

Rutas y vistas

En este capítulo, vamos a presentar la manera más sencilla de mostrar una vista (es decir, que podamos ver algo por la pantalla del navegador) y esto es empleando las rutas en combinación con las vistas que forman parte de nuestro MVC; como comentamos al inicio del curso; Laravel no es un framework MVC puro, si no, tiene agregados o variantes en los cuales existen varias formas de hacer lo mismo; y esta es una de estas variantes.

Caso práctico

Vamos a crear una nueva ruta:

Route::get('/contact', function () {
    return view('contact');
})->name('contact');

Si vamos al navegador:

Página de contacto
Página de contacto

Verás el mensaje que imprimimos anteriormente; puedes hacer exactamente lo mismo empleando el echo en vez del return. Vamos a crear una vista asociada:

resources\views\contact.blade.php

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <h1>Contact</h1>   
</body>

</html>
La referenciamos en la ruta:
Route::get('/contact2', function () {
    return view('contact2');
})->name('contact2');

Y si vamos al navegador:

Segunda página de contacto
Segunda página de contacto

Verás la representación del código anterior.

Pase de parámetros

Para pasar parámetros a la vista; basta con indicar a la función de view() un segundo parámetro que debe ser un array en el cual colocamos la pareja de key y value del mismo:

Route::get('/contact', function () {
    $name = 'Andres'
    return view('contact',['name'=>$name]);
})->name('contact');
  1. La key del array va a ser empleada por Laravel de manera interna para construir una variable, que es la que podemos usar en la vista.
  2. El valor/value del array, será el valor que tendrá asignada la variable generada anteriormente.

Así que, para consumir la variable anterior, tenemos:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <h1>Contact</h1>   
    <p>{{$name}}</p>
</body>
</html>

O

***
<p><?= $name ?></p>
***

El código PHP anterior, viene siendo PHP básico, pero qué pasa con blade; en blade, para imprimir valores, podemos usar la siguiente sintaxis:

***
<p>{{$name}}</p>
***

Que claro está es mucho más limpia y sencilla que la anterior.

Si necesitas pasar más variables, lo colocas como un elemento más en tu array de datos:

***
return view("web/contact", ["name" => $name,"var2" => $other,...]);
***

En general, puede pasar cualquier cosa que puedas almacenar en una variable como strings, números, objetos, etc.

Controladores

En Laravel, un controlador es un componente que se encarga de manejar las solicitudes HTTP que recibe la aplicación. Es decir, los controladores son el intermediario entre las rutas y las vistas

Los controladores en Laravel son uno de los mecanismos que tenemos al momento de desarrolar las aplicaicones en Laravel de agrupar funcionalidades; es decir, si queremos crear un post, creamos un controlador, al igual que si queremos tener un listado o eliminar un post; los controladores son clases, que agrupan un conjunto de funciones relacionadas con las cuales podemos administrar nuestros recursos.

Por buenas práticas, los controladores deben de tener una estructura simple, limpia y escalable; en los controladores podemos hacer toda clase de operaciones como por ejemplo, hacer validaciones, conectarse a los modelos, otros servicios, usar funciones de ayuda… y finalmente devolver una vista, un texto, un json entre otros.

En resumen, un controlador en Laravel es una clase que agrupa la lógica de las solicitudes HTTP relacionadas y es responsable de manejar las solicitudes para devolver una respuesta.

En Laravel, un controlador es un componente que se encarga de manejar las solicitudes HTTP que recibe la aplicación. En otras palabras, un controlador es el intermediario entre las rutas de la aplicación y las vistas que se muestran por pantalla.

Rutas

Como mencionamos antes, las rutas son la primera capa que se ejecuta al momento de realizar una petición de un proyecto en Laravel; aqui, es donde se configuran las entradas de la aplicación; por ejemplo, si queremos una ruta para mostrar los posts para nuestro blog, la configuramos aqui:

blog/

blog/listado

O similares, lo mismo, para cualquier otra ruta.

En las rutas, aparte de definir el acceso, tambien se configura cual controlador resuelve la ruta especificada y el tipo de método, es decir, de tipo GET, POST, PUT, PATH o DELETE; solamente las primeras dos son las que pueden ser resueltas directamente por el navegador, el resto, pueden ser resueltas usando peticiones HTTP de otro tipo, como peticiones fetch, axios en JavaScript o con cualquier otra tecnología que uses, como Flutter, Vue…

En Laravel, las rutas se definen en el archivo llamado routes/web.php. Por ejemplo, una ruta definida en Laravel podría parecerse a esto:

Route::get('/ejemplo', 'ControladorEjemplo@metodoEjemplo');

En este ejemplo, se define una ruta para una solicitud GET a la URL "/ejemplo". Cuando se recibe una solicitud que coincide con esta ruta, el método "metodoEjemplo" en el controlador "ControladorEjemplo" se ejecutará para manejar la solicitud.

Rutas en la práctica

Ya con nuestro ecosistema para trabajar en Laravel instalado y nuestro proyecto creado, lo siguiente que vamos a hacer sería ver cómo podemos crear algo interesante para verlo mediante nuestro navegador.

Vamos a crear una ruta para eso vamos a ir al archivo:

laratest\routes\web.php

En nuestro caso laratest es el nombre de nuestro proyecto

Rutas de un proyecto Laravel

Y vamos a ver cómo está formado él mismo, tal cual puedes ver, ya tenemos algunas rutas configuradas que es la que está empleando nuestra aplicación:

Route::get('/', function () {
    return view('welcome');
});

Y esta que vamos a evaluar un poco:

Route::get('/home', 'HomeController@index')->name('home');

Como puedes ver, la estructura de una está formada de 3 elementos principales:

  1. La URI
  2. El controlador
  3. La función dentro del controlador, que es la que se va a encargar de hacer el proceso

Así que, nada impide que podamos crear nuestras propias rutas; pero las rutas también tienen una funcionalidad bastante interesante que es la que nos permiten definir lógica, en otras palabras implementar la funcionalidad que queramos hacer; esto obviamente rompe con nuestro MVC y solo es recomendado si queremos usarlo para hacer algo sencillo como hacer unos pocos pasos o mostrar una vista y que esa reciba pocos datos o ninguno.

Tipos de rutas

En Laravel, tenemos tantos tipos de rutas como métodos http, que sería para los métodos de tipo get, post, put, patch, o delete, contamos con rutas con el mismo nombre en Laravel:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

Por lo tanto, si queremos crear una para que podamos consultar al momento de acceder a la misma desde el navegador, sería de tipo get:

Route::get('/', function () {
});

Y en la misma podemos definir algún cuerpo, por ejemplo una impresión de un texto plano:

Route::get('/', function () {
    return "Hola mundo";
});

Y si vamos a nuestro navegador veremos:

Ruta con texto

Que viene siendo una representación del texto que definimos anteriormente.

Establecer un vista para la ruta anterior

Ahora, claro que mostrar solo un texto no viene siendo lo más interesante del mundo, podemos hacer algo más elaborado como indicar una vista en Laravel; para eso tenemos que crear una vista que sería un archivo con extensión .php en la ubicación de:

laratest\resources\views\

Por ejemplo, ya nosotros tenemos una lista que es la que emplea por defecto nuestro framework, como puedes ver, se llama welcome.blade.php y si vemos la ruta que carga la misma:

Route::get('/', function () {
    return view('welcome');
});

Hay una relación de uno a uno entre el nombre de la vista y la referencia que empleamos mediante la función de ayuda llamada view, así que nada nos impide crear una vista llamada home.php o home.blade.php y enlazarla de la siguiente manera:

Route::get('/', function () {
    return view('home');
}); 

Aquí nosotros tenemos un par de variaciones para tratar con archivos de vista, la que sería incluir el sufijo de .blade al nombre del archivo de la vista; generalmente nosotros queremos que nuestras vistas puedan soportar el motor de plantillas que nos ofrece Laravel conocido como Blade, para poder emplear la sintaxis de Blade en nuestro archivo; lo que significas que si no le colocas el sufijo de .blade, NO podrás emplear la sintaxis de Blade.

Y en la vista de welcome, podemos colocar cualquier contenido HTML por ejemplo:

<h1>Hola Mundo</h1>

Pero como puedes ver, es un contenido estático, y como nosotros estamos  empleando PHP mediante un framework está más que claro que podemos pasar datos de manera dinámica, y estos pueden e ir de una base de datos, conexión a otra API, etc: por ejemplo, para pasar datos a esta vista; de momento, vamos a crear una sencilla vista llamada home:

laratest\resources\views\home.blade.php:

Con el siguiente contenido:

<h1>Hola Mundo</h1>

Y si definimos nuestra ruta como:

Route::get('/', function () {
    return view('home');
});

Y vamos al navegador:

Ruta página HTML

Buala! Veremos el contenido que definimos anteriormente.

Pasar datos de manera dinámica a la vista

Podemos acceder al valor que nosotros estamos pasando e imprimirlo; aún no hemos trabajado con Blade; pero para imprimir una variable lo podemos hacer de la siguiente manera:

<h1>Hola {{name}}</h1>

Que internamente Laravel lo va a traducir a lo siguiente:

<h1>Hola <?php echo e($name); ?></h1>

Que como puedes ver, es simplemente HTML plano; estas traducciones de vistas las puedes encontrar en storage/framework/views.

Y si vamos a nuestro navegador veremos lo siguiente:

Ruta página html contenido dinámico

Pasando datos de la ruta a la vista

Ahora vamos a adaptar nuestra ruta, y vamos a pasarle un texto estático; por eso lo podemos definir como siguiente parámetro, en el cual el dato que vamos a pasar lo tenemos que definir dentro de un array ya que podemos pasar más que un simple dato a la vista si no tanto como necesitemos, pero de momento solamente vamos a pasar un solo dato:

Route::get('/', function () {
    return view('home',['name'=>'Andrés']);
});

Y en nuestra vista vamos a hacer el siguiente cambio:

<h1>Hola <?php echo e($name); ?></h1>

Ahora si vamos a nuestro navegador:

Ruta página html contenido dinámico

Veremos que imprime el valor que definimos en la ruta; con esto te puedes hacer una idea de lo interesante de todo esto y de cómo funcionan los controladores.

Conclusiones

Como ves, también funciona perfectamente para poder imprimir simplemente un texto; ahora tienes una idea más clara de qué va todo esto y de porqué tenemos que emplear controladores para hacer operaciones más interesantes; ya que suponte que necesitas un modulo para por ejemplo hacer un CRUD de alguna relación como personas, por lo tanto cuantas rutas crees que necesites; al menos unas 7:

GET|HEAD  | dashboard/category                 | category.index
POST      | dashboard/category                 | category.store
GET|HEAD  | dashboard/category/create          | category.create
DELETE    | dashboard/category/{category}      | category.destroy
PUT|PATCH | dashboard/category/{category}      | category.update
GET|HEAD  | dashboard/category/{category}      | category.show
GET|HEAD  | dashboard/category/{category}/edit | category.edit

Y si ahora necesitas crear dos CRUD más, o tal vez 5... definir todo esto en un archivo de ruta no viene siendo lo recomendado; tendremos una mejor organización y más control si definiremos toda esta lógica en una capa -controlador- para crear un CRUD específico para cada operación que vayamos a realizar; pero de esto nos ocupamos en la siguiente entrada, manejo formularios en Laravel.

Extra: Modularizar Rutas mediante funciones Laravel - VENTAJAS!

Extra: Modularizar Rutas mediante funciones Laravel - VENTAJAS!
Video thumbnail

Te quiero hablar aquí un poquito sobre cómo puedes modularizar tus rutas, la rutas que presentamos antes, al empezar a crear controladores pueden crecer sin control, ya que uno de los “problemas”, entre comillas, que podemos tener en Laravel son las benditas rutas y veamos como las puedes ir creando desde una fase temprana de manera organizada.

Usualmente todas se encuentran definidas al mismo nivel, o la parte de agrupado no forma parte como tal de una organización clara, sino que responde a una necesidad específica, dependiendo de cómo quieras presentar un módulo.

Por ejemplo:

  • Si un módulo está protegido, entonces colocas ciertas rutas.
  • Si comienza con cierto patrón, colocas otras rutas.
  • Si quieres ejecutar un middleware, agregas otro grupo de rutas.

Pero otra vez: esto no forma parte de una modularización real.

¿A qué me refiero con modularizar?

Me refiero a colocar las rutas directamente en módulos separados. Por ejemplo, en mi aplicación de academia (la web de academia que estás viendo acá), manejo algunas rutas, aunque prácticamente nada, porque es una aplicación en Vue, entonces todo lo maneja Vue.

Tengo el blog y la parte de gestión, lo que sería como tres módulos. Entonces, es ahí donde digo: “pudiéramos agrupar las rutas”.

Formas de modularizar rutas
Tenemos un par de formas para modularizar:

1 Dentro del mismo archivo

Es la forma más sencilla y la que le serviría a la gran mayoría. Simplemente defines funciones dentro del archivo de rutas. A veces esto se pasa por alto, pero recuerda que estamos en PHP, por lo tanto puedes usar cualquier cosa de PHP: funciones, clases, etc.

Aunque usar clases para esto me parece algo más rebuscado, con funciones ya funciona bastante bien.

Entonces, ¿qué hago yo? Defino funciones como rutasDashboard(), las agrupo ahí; rutasBlog(), las agrupo también, y luego defino dónde se van a emplear, por ejemplo en una condición if.

if (condición) {
   rutasDashboard();
}

O mediante subdominios:

if (app()->environment('production')) {
   // Uso el subdominio
   Route::domain('dashboard.miapp.com')->group(function () {
       rutasDashboard();
   });
} else {
   // Uso un prefijo en el path
   Route::prefix('dashboard')->group(function () {
       rutasDashboard();
   });
}

2. Archivos separados

También puedes crear archivos independientes, por ejemplo:

  • rutas_dashboard.php
  • rutas_academia.php
  • rutas_blog.php

Ahí defines tus rutas y luego las importas en tu archivo principal.

Esta opción es útil si tienes muchísimas rutas y ya se hace difícil leer o mantener todo en un solo archivo.

Conclusión

Entonces, recapitulando:

  • Puedes modularizar rutas usando funciones dentro del mismo archivo.
  • Si tienes muchas, puedes usar archivos separados.
  • Puedes aprovechar condiciones para distinguir entre producción y local.
  • Y puedes evitar la duplicación y el desorden agrupando las rutas de manera clara.

Extra: Cuando usar las propiedades de las Clases Controladoras en Laravel

Video thumbnail

Esto es un poco más avanzado, pero es importante que entiendas cuando puedes usar las propiedades en clases de tipo controladores en Laravel, de doy mi opinión.

En Laravel, los métodos definidos para responder a una petición (las llamadas "funciones controladoras") a menudo abandonan las bases de la Programación Orientada a Objetos (POO). Es crucial recordar que un controlador es, ante todo, una Clase, lo que nos permite aprovechar la herencia y, más importante aún, el uso de propiedades de clase.

El uso de propiedades puede simplificar la gestión de datos comunes a múltiples métodos y nos ayuda a modularizar la aplicación.

1. Caso Simple: La Propiedad $baseURL

Un ejemplo básico y útil es la centralización de URLs que se usan en varias partes de la clase:

class BasePaymentController extends Controller
{
   // ...
   protected $baseURL = 'https://api-m.paypal.com';
   public function __construct()
   {
       // Se inicializa el valor en el constructor.
       $this->baseURL = config('app')['env'] == 'local' ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
       // ...
   }
}

Uso: La propiedad $baseURL se inicializa en el constructor. El constructor actúa como un middleware que se ejecuta antes de cualquier método controlador, permitiendo inicializar valores clave (como Client ID, Secret y Base URL).

Beneficio: De esta forma, cualquier método que necesite la URL de PayPal (para generar el token, verificar o cobrar el pago) simplemente accede a $this->baseURL, garantizando la correcta URL de sandbox o producción.

2. Caso Complejo: Unificando Respuestas de Pago

El uso de propiedades se vuelve indispensable al manejar múltiples plataformas de pago (PayPal y Stripe) que ofrecen respuestas heterogéneas. El objetivo es unificar la información clave del pago y hacerla accesible a otros métodos de forma transparente.

class BasePaymentController extends Controller
{
   protected int|float $price = 0;
   protected string $status = '';
   protected string $idAPI = ''; // ID de la orden o sesión
   protected array|object $responseAPI;
   protected string $payment = 'paypal';
  protected function sendRequestAPI(string $orderId)
  {
      // ... Lógica para verificar si es Stripe o PayPal ...
      
      if ($orderId == 'stripe') {
          // ... Lógica específica de Stripe ...
          $this->status = 'COMPLETED'; // Estatus Unificado
          $this->idAPI = request("stripe_session_id");
          $this->price = intdiv($this->responseAPI->amount_total, 100);
          $this->payment = 'stripe';
      } else {
          // ... Lógica específica de PayPal ...
          $this->status = 'COMPLETED'; // Estatus Unificado
          $this->idAPI = $this->responseAPI['id'];
          $this->price = $this->responseAPI['purchase_units'][0]['payments']['captures'][0]['amount']['value'];
      }
  }
}

Existen varios elementos que son comunes a cualquier pago:

  • ropiedad    Dato Requerido    Ejemplo de Unificación
  • $responseAPI    La traza completa de la respuesta de la API.    Se almacena toda la información del payload de PayPal/Stripe para disputas.
  • $status    Estatus de la transacción.    Se convierte el estatus nativo de la API (ej., paid en Stripe o 'COMPLETED' en PayPal) al estatus interno unificado (COMPLETED).
  • $price    El monto real cobrado.    Se realiza la conversión (ej., dividiendo por 100 si la API devuelve el valor en centavos) para almacenar el monto real.
  • $idAPI    El ID de referencia.    Se asigna el orderId (PayPal) o session_id (Stripe) a una única propiedad.
  • $payment    La plataforma usada.    Se establece paypal o stripe para registro.

En resumen, muchas veces vamos a necesitar implementar propiedades que empleamos en distintos métodos controladores y cuyo valor o inicialización no depende de la petición del usuario o cuando usamos la herencia o los trait y estas clases implementan propiedades que luego podemos usar desde los controladores.

Acepto recibir anuncios de interes sobre este Blog.

Vamos a aprender a emplear las rutas en Laravel de manera básica, su estructura y cómo podemos emplear las rutas para crear funciones sencillas que devuelvan textos y vistas.

| 👤 Andrés Cruz

🇺🇸 In english