Novedades en Laravel 5: Enrutamiento

  • #laravel
  • #php

El enrutamiento sufre un lavado de cara en Laravel 5, dando soporte a cacheo de rutas y middleware que se ejecutará en las rutas indicadas.

El enrutamiento en Laravel 5 ha recibido dos nuevas funcionalidades: cacheo de rutas y middleware (antiguos filtros before y after). También se han eliminado las anotaciones de las que hablaremos al final del artículo.

Cacheo de rutas

Conocida como route caching, esta nueva funcionalidad permite cachear nuestro fichero de rutas (routes.php) para que no tenga que procesarse en cada petición. Como ventaja, si nuestro sitio web es muy grande o contiene una gran cantidad de rutas, veremos un incremento en el rendimiento y en el tiempo de carga.

Para sitios pequeños o con pocas rutas, no merece la pena puesto que añade el inconveniente de tener que refrescar la caché con cada cambio que hagamos en nuestro fichero de rutas, algo que se nos puede olvidar que estamos usando.

Los nuevos comandos son php artisan route:cache para cachear las rutas y php artisan route:clear para desactivar la característica.

Middleware

Los antiguos filtros before y after de Laravel 4 aún siguen disponibles en Laravel 5, pero en esta nueva versión se ha incluído un nuevo método preferido llamado middleware.

Un middleware es una especie de módulo que envuelve nuestra aplicación y se ejecuta antes de procesar la petición o antes de entregar la respuesta (salvo el terminatable middleware).

Es decir, las peticiones pasan a través del middleware de entrada antes de llegar al corazón de nuestra aplicación (controladores, rutas...) y una vez tengamos la respuesta, ésta pasará nuevamente por el middleware de salida si lo hubiera.

Cómo generar un nuevo middleware

El nuevo comando php artisan make:middleware MiddlewareName genera un fichero de ejemplo con el siguiente contenido:

app/Http/Middleware/MiddlewareName.php
PHP
namespace App\Http\Middleware;

use Closure;

class MiddlewareName
{

  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
    // ...
  }
}

El contenido de nuestro middleware irá dentro de la función handle.

Si queremos que nuestro middleware actúe antes de procesar la petición (como un filtro before), llamaremos a la función anónima (closure) justo después de ejecutar nuestro middleware, tal que así:

PHP
public function handle($request, Closure $next)
{
  // Nuestro middleware
  return $next($request);
}

Si por otro lado, queremos un middleware que actúe después de procesar la petición y antes de enviar la respuesta (como un filtro after), lo haremos de la siguiente manera:

PHP
public function handle($request, Closure $next)
{
  $response = $next($request);
  // Nuestro middleware
  return $response;
}

Cómo utilizar nuestro middleware

Para utilizar nuestro middleware vamos a editar el fichero App/Http/Kernel.php. En él encontramos dos arrays.

El primer array contiene middleware que se ejecutará siempre, en cada petición.

App/Http/Kernel.php
PHP
protected $middleware = [
  'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
  'Illuminate\Cookie\Middleware\EncryptCookies',
  'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
  'Illuminate\Session\Middleware\StartSession',
  'Illuminate\View\Middleware\ShareErrorsFromSession',
  'App\Http\Middleware\VerifyCsrfToken',
];

El segundo array contiene middleware que será ejecutado solamente cuando lo especifiquemos.

App/Http/Kernel.php
PHP
protected $routeMiddleware = [
  'auth' => 'App\Http\Middleware\Authenticate',
  'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
  'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];

¿Cómo podemos especificarlo? Muy sencillo, pero hay dos maneras.

La primera forma de hacerlo es en nuestro fichero de rutas:

routes.php
PHP
// Única ruta
$router->get('/post/create', 'PostsController@create', ['middleware' => 'auth']);

// Múltiples rutas
$router->group(['middleware' => 'auth'], function() {
  $router->get('/post/create', 'PostsController@create');
  // ...
});

La segunda manera, especificando nuestro middleware dentro de los controladores utilizando $this->middleware() de la siguiente manera:

PHP
class PostsController extends Controller {

  public function __construct()
  {
    $this->middleware('auth');
    $this->middleware('log', ['only' => ['create', 'store']]);
    $this->middleware('checkRoles', ['except' => ['index', 'show']]);
  }

}

Middleware final

Terminatable middleware es el término que han dado para nombrar al middleware que se ejecuta pasivamente una vez se haya enviado la respuesta al usuario.

Este tipo de middleware debe implementarse de la siguiente manera:

PHP
use Illuminate\Contracts\Routing\TerminableMiddleware;

class MiddlewareName implements TerminableMiddleware {

  public function handle($request, $next)
  {
    return $next($request);
  }

  public function terminate($request, $response)
  {
    // Nuestro middleware final
  }

}

Es decir, debe usar e implementar la clase TerminableMiddleware y además debe ejecutarse dentro de la función terminate.

Recuerda que debemos incluir este middleware en uno de los dos arrays de Kernel.php, siendo más común incluirlo en el array global.

Eliminación de anotaciones

Las anotaciones han sido eliminadas del proyecto y ahora pertenecen a una librería externa que se puede incorporar a Laravel 5 en forma de paquete.

Las anotaciones son una forma de generar o manipular rutas en base a los comentarios de nuestros ficheros. Puedes leer más acerca de las anotaciones en la wiki del paquete annotations.

Básicamente, este paquete es capaz de leer comentarios de este tipo:

PHP
namespace App\Http\Controllers;

class PostsController {

  /**
   * Show the Index Page
   * @Get("/", as="index", middleware="guest")
   */
  public function getIndex()
  {
    return view('index');
  }

}

Y convertirlo en una ruta de este tipo:

storage/framework/routes.scanned.php
PHP
$router->get('/', [
  'uses' => 'App\Http\Controllers\PostsController@index',
  'as' => 'index',
  'middleware' => ['guest'],
  'where' => [],
  'domain' => NULL,
]);

Compartir en