rutas-con-filtros-laravel-5-1

Hoy vamos a aprender a agregar filtros a nuestras rutas de Laravel 5.1 que permitan verificar la data que el usuario está enviando (a través de la url) para redirigirlo a la acción correcta, sin necesidad de utilizar middleware, validaciones u otro tipo de estructura de control, tan solo haciendo uso del método where() dentro el archivo de rutas.

El componente de rutas de Laravel permite capturar las peticiones realizadas por un usuario, de tal manera que podamos evaluar los parámetros enviados y devolver la respuesta acorde a cada petición. Cuando iniciamos un nuevo proyecto, las rutas se establecen por defecto dentro del archivo routes.php en el directorio app\Http, en este archivo podrás ver algo similar a esto:

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

Esta es una ruta de tipo GET que devuelve una vista llamada welcome (recuerda que en Laravel las vistas se almacenan en el directorio resources/views, utilizando la extensión .blade.php).

Route::get('user', function () {
    return "foo";
});

Route::post('user', function () {
    return "bar";
});

En este caso tenemos dos rutas hacia el mismo url /user, diferenciadas por el tipo de petición, una es de tipo POST (para enviar datos desde un formulario) y otra de tipo GET, de esta forma usando un tipo diferente indicamos cual de ellas debe encargarse de cada solicitud. Por ejemplo, una para mostrar el formulario de registro de usuarios y la otra para almacenar los datos que este formulario envié.

En las rutas también podemos recibir parámetros cómo:

Route::get('user/{id}', function ($id) {
    return $id;
});

En este caso vamos a recibir por medio de la variable $id, por ejemplo, el identificador de un usuario en la base de datos, ahora, que tal si queremos recibir como parámetro en otra ruta el nombre del usuario pero usando el mismo slug:

Route::get('user/{id}', function ($id) {
    return $id;
});

Route::get('user/{name}', function ($name) {
    return $name;
});

¿Ves a dónde quiero llegar?

Si tenemos dos rutas del mismo tipo, con el mismo slug (/user/) y recibiendo los parámetros bajo la misma estructura, podemos enfrentarnos a un problema, ya que probablemente todas las peticiones de tipo /user/nombre, /user/10 van a ser capturadas por la misma ruta, en este caso la primera en orden descendente.

De seguro eres un programador cuidadoso y has tomado todas las precauciones para que esto no te ocurra, pero, puedes enfrentarte a esta situación cuando tratas de migrar la data o la estructura de un viejo sitio web a uno nuevo hecho en Laravel y no quieres que estas antiguas url’s estén arrojando 404 cuando un usuario intenta acceder o algo por el estilo, entonces, es aquí donde podemos aprovechar el uso de filtros en las rutas.

Filtros en rutas

Los filtros se pueden utilizar haciendo uso de expresiones regulares, por ejemplo, queremos que en el primer bloque capture solo las variables de tipo numérico ($id).

Route::get('user/{id}', function ($id) {
    return $id;
})->where(['id' => '[\d]+']);

Route::get('user/{name}', function ($name) {
    return $name;
});

Entonces desde ahora todas las rutas de tipo /user/10, van a ser capturadas por la primera ruta, pero ¿Qué ocurre con los datos de tipo string?, la respuesta es sencilla, podemos asegurarnos de usar la misma estructura:

Route::get('user/{id}', function ($id) {
    return $id;
})->where(['id' => '[\d]+']);

Route::get('user/{name}', function ($name) {
    return $name;
})->where(['name' => '[-\w]+']);

Inclusive, puedes limitar a una lista específica de posibles valores. Digamos que además del problema que ya tienes al usar user/{name} y user/{id}, tu sistema debe ser capaz de manejar posibles peticiones de tipo user/create, user/delete, /user/update. Si ingresas cualquiera de estas url, la petición va a ser capturada por la segunda ruta, pero eso no es lo que queremos, vamos a solucionarlo fácilmente.

Route::get('user/{id}', function ($id) {
    return $id;
})->where(['id' => '[\d]+']);

Route::get('user/{slug}', function ($slug) { 
    return $slug; 
})->where(['slug' => 'create|delete|update']);

Route::get('user/{name}', function ($name) {
    return $name;
})->where(['name' => '[-\w]+']);<br>

En este caso debemos asegurarnos que la ruta que posee la restricción este primero para que pueda ser evaluada correctamente.

Desde ahora cuando se trate de user/delete, user/update, user/create, las peticiones van a ser capturadas por este segundo bloque ya que has definido explícitamente cuáles son los posibles valores de ese {slug} y cualquier valor de tipo string que esté fuera de esa lista va a ser capturado por la tercera ruta.  Finalmente podemos probar todo esto con el siguiente código:

Route::get('user/{id}', function ($id) {
    return "Esto es un ID:".$id;
})->where(['id' => '[\d]+']);

Route::get('user/{slug}', function ($slug) {
    return "Esto es un Slug:".$slug;
})->where(['slug' => 'create|delete|update']);

Route::get('user/{name}', function ($name) {
    return "Esto es un Nombre:".$name;
})->where(['name' => '[-\w]+']);

Ahora puedes probar cada ruta en tu navegador y podrás ver como se devuelve el resultado esperado.

Espero que te haya gustado esta lección, no olvides dejar tus dudas en la sección de comentarios, te espero en una próxima lección.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Facades personalizados en Laravel 5.1 Lección siguiente Guía rápida de Laravel - Nivel intermedio