Skip to content

Commit

Permalink
Added: New posts [0021-0023] (#13).
Browse files Browse the repository at this point in the history
  • Loading branch information
kennyhorna committed Feb 29, 2020
1 parent edad3e4 commit 5172132
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ categories: [laravel, php, programming, librerias]

Junto con el lanzamiento de Laravel 7.X, se lanza Laravel Airlock. Airlock es una librería mantenida por el equipo de Laravel que permite una autenticación algo más simple y ligera para SPAs, aplicaciones móviles y APIs basadas en tokens. Veamos cómo funciona.

------

Este artículo pertenece a la serie [Novedades de Laravel 7](/blog/0021-novedades-de-laravel-7). Puedes leer sobre el resto de sus novedades [aquí](/blog/0021-novedades-de-laravel-7).

-----

## Fundamentos

### ¿Qué es en sí?
Expand Down Expand Up @@ -180,3 +186,5 @@ Puedes leer más sobre esto [aquí](https://laravel.com/docs/master/airlock#test
# Cierre

Como podemos ver, Airlock nos ofrece una alternativa fácil de implementar que puede ser de utilidad en muchos escenarios.

Si te interesó esta librería, no olvides leer el resto de novedades que trae Laravel 7 ([aquí](/blog/0021-novedades-de-laravel-7)), ya que tenemos [una serie de artículos -"Novedades de Laravel 7"-](/blog/0021-novedades-de-laravel-7) dedicados a este tema.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: "Buenas prácticas en Laravel: Convenciones de nombrado"
date: 2020-02-22
description: "Casi todo aspecto en Laravel es configurable para que puedas adaptarlo a tus costumbres. Sin embargo, Laravel de por sí tiene un modo de nombrar distintos elementos que te pueden ahorrar estos ajustes adicionales en caso decidas mantener sus prácticas. Hoy veremos cuales son."
cover_image: /assets/images/posts/0020/0020-laravel-convenciones-de-nombrado-nombres.png
featured: true
featured: false
categories: [laravel, php, tips]
---

Expand Down
42 changes: 42 additions & 0 deletions source/_posts/0021-novedades-de-laravel-7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
extends: _layouts.post
section: content
title: "Novedades de Laravel 7"
date: 2020-02-28
description: "Como en cada nueva versión, Laravel 7 nos trae una serie de nuevas funciones y mejoras. Esta lista pretende resaltar cada una de estas novedades, mejoras y correcciones."
cover_image: /assets/images/posts/0021/0021-novedades-laravel-7.png
featured: true
categories: [laravel, php, programming, series]
---

Este **3 de marzo** se realizará el lanzamiento oficial de **Laravel 7**. Como en cada nueva versión, Laravel nos trae una serie de nuevas funciones y mejoras. Esta lista pretende resaltar -en lo posible- cada una de estas.

Entre las novedades que Laravel nos trae en esta versión, tenemos:

- [Laravel Airlock: Autenticación ligera para SPAs y APIs](/blog/0019-laravel-airlock-autenticacion-ligera-para-spas-y-apis)
- [Mejoras en el enlazado de modelos a rutas (_Route Model Binding_)](/blog/0022-novedades-de-laravel-7-mejoras-en-el-enlazado-de-modelos-a-rutas)
- [Cliente HTTP](/blog/0023-novedades-de-laravel-7-cliente-http)
- _Operaciones fluidas trabajando con Strings_
- _Múltiples drivers para emails_
- _Casting personalizado en Eloquent (Eloquent Custom Casts)_
- _Etiquetas en componentes Blade y mejoras_
- _Mejoras de rendimiento en el cacheo de Rutas (Route Caching)_
- _Soporte nativo para CORS_
- _Casting en tiempo de Ejecución (Query time casts)_
- _Mejoras de rendimiento en el manejo de Colas en MySQL 8+_
- _Comando ``test`` de Artisan_
- _Mejora en las plantillas Markdown para Emails_
- _Markdown Mail Template Improvements_
- _Personalización de Stubs_

> Las referencias a este listado se irán actualizando a medida que se publiquen más artículos.
----

## Cierre

Como podrás notar, Laravel 7 no se queda atrás a la hora de **incluir novedades**. De hecho -según el mismo Taylor Otwell- esta versión es de las que más funcionalidad introducirá en comparación con los lanzamientos de los últimos años.

<div>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I think you have to go back to Laravel 5.5 (August 2017) to find a Laravel release as nice as Laravel 7.x will be. 🏄‍♂️ Hear about it at <a href="https://twitter.com/LaraconOnline?ref_src=twsrc%5Etfw">@LaraconOnline</a></p>&mdash; Taylor Otwell 🏝 (@taylorotwell) <a href="https://twitter.com/taylorotwell/status/1222551807907586048?ref_src=twsrc%5Etfw">January 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
extends: _layouts.post
section: content
title: "Novedades de Laravel 7: Mejoras en el enlazado de modelos a rutas"
date: 2020-02-28
description: "Como en cada nueva versión, Laravel 7 nos trae una serie de nuevas funciones y mejoras. En este artículo destacaremos las mejoras hacia el enlazado de modelos a rutas (Route Model Binding)."
cover_image: /assets/images/posts/0022/0022-novedades-laravel-7-mejoras-en-el-enlazado-de-modelos-a-rutas.png
featured: false
categories: [laravel, php, programming]
---

Como en cada nueva versión, Laravel 7 nos trae una serie de nuevas funciones y mejoras. En este artículo destacaremos las mejoras hacia el **enlazado de modelos a rutas** (_Route Model Binding_).

------

Este artículo pertenece a la serie [Novedades de Laravel 7](/blog/0021-novedades-de-laravel-7). Puedes leer sobre el resto de las características introducidas en esta versión [aquí](/blog/0021-novedades-de-laravel-7).

-----

### Enlazado implícito de Modelos a Rutas

Desde versiones anteriores (v5.2+) Laravel nos da la posibilidad de **enlazar implícitamente modelos a parámetros de rutas** (_Route Model Binding_). Laravel realiza esto deduciendo el nombre del modelo desde la definición de la ruta en sí.

Antes de la introducción de esta funcionalidad en aquella versión, teníamos que hacer más trabajo. Por ejemplo, para una ruta que muestre el detalle de una **tienda**, hubiéramos hecho:

# routes/web.php

Route::get('stores/{id}', 'StoreController@show');

Por lo que luego, tenías que buscar el objeto en cuestión inyectando el ``$id`` para finalmente hacer la consulta directamente en el controlador:

# app/Http/Controllers/StoreController.php

public function show ($id)
{ // ^^^^
$store = Store::find($id);
return $store;
}

Con la introducción del **enlazado implícito de modelos en rutas** -en Laravel 5.2-, esto se facilitó. Tan solo hacía falta modificar la ruta de la siguiente manera:

Route::get("stores/{store}", 'StoreController@show');

De este modo, Laravel intentará encontrar un modelo que corresponda con el parámetro de ruta (``Store``), pudiendo así resolver el modelo e inyectarlo hacia nuestro controlador:

public function show (Store $store)
{ // ^^^^^
return $store; // <--
}

Sin embargo, **¿qué pasa si no queremos buscar por la llave primaria del modelo -típicamente el ``id``- sino por alguna otra columna?**

Tomemos el caso de un **Artículo** (modelo ``Post``). Quizás querríamos buscar por el ``slug`` del título, en lugar del ``id`` del artículo en sí. Previo a Laravel 7, se le tenía que indicar a nuestro modelo cómo es que debía de resolver estos enlazados implícitos:

# app/Post.php

public function getRouteKeyName()
{
return 'slug'; // <-- nombre del atributo/columna
}

El detalle de esta solución es que este cambio **regirá para todas las rutas** que quieran resolver modelos ``Post``. Entonces, ¿qué sucede si en otro lugar de nuestra aplicación, necesitamos buscar por un campo **distinto** a ``slug``? Quizás en el administrador deseamos ahora sí buscar por ``id`` o por ``uuid``. En fin, nos obligaba a volver a la solución inicial, buscando manualmente en cada método que lo necesite.

Esto quedará en el pasado con las nuevas versiones de Laravel.

### Mejoras en Laravel 7

En Laravel 7, si queremos resolver el modelo por **algún campo en específico distinto al de la llave primaria**, tan solo tenemos que indicarlo en la misma definición de la ruta con la notación ``:columna``. Veamos un ejemplo:

Route::get("posts/{post:slug}", 'PostController@show');
// ^^^^^^^^^

Así de simple. Ahora, lo _cool_ de esto es que nos da la flexibilidad de poder definir distintas rutas con diferentes modo de resolución de manera simple:

Route::get('posts/{post:slug}', 'PostController@show');
// ^^^^^^^^^
Route::get('admin/posts/{post:uuid}', 'AdminPostController@show');
// ^^^^^^^^^

Genial.

### Filtros automáticos

Hay escenarios en los cuales implícitamente enlazas múltiples modelos en una misma definición de ruta, **y quieres filtrar los resultados de uno respecto del otro**. Tomemos el caso de un **autor** (``Author``) con sus **artículos** (``Post``).

Route::get("authors/{author}/posts/{post:slug}", "AuthorPostController@index");
// ^^^^^^ ^^^^^^^^^

En Laravel 7, cuando uses una llave personalizada para resolver modelos implícitamente, automáticamente se aplicará un filtro (Query scope) tratando de deducir el nombre de las relaciones entre ambos modelos.

En el ejemplo anterior, Laravel intentará buscar la relación ``posts()`` en el modelo ``Author``, de este modo al tratar de resolver los artículos/_posts_ de un author en específico, internamente **aplicará un filtro para limitar los resultados del segundo modelo, respecto del primero**. Entonces, solo recibiremos los artículos/_posts_ que **pertenezcan** a ese autor en específico.

Esto es particularmente útil pues, personalmente he tenido situaciones de este tipo y siempre suelo colocar un _check_ adicional al recibir los modelos para garantizar que efectivamente estén vinculados. Siempre puede suceder el caso en el que un usuario pueda querer acceder a realizar operaciones en los recursos a los cuales no debería tener acceso.

Para leer más detalles sobre esta sección, visita [esta sección](https://laravel.com/docs/master/routing#route-model-binding) de la documentación oficial.

-----

## Cierre

Como puedes notar, este pequeño -pero interesante- cambio nos puede ahorrar unas cuantas líneas de código extra que ahora podremos dedicar a mejorar nuestra lógica de negocio.

Si te interesó esta nueva funcionalidad, no olvides leer el resto de novedades que trae Laravel 7 ([aquí](/blog/0021-novedades-de-laravel-7)), ya que tenemos [una serie de artículos -"Novedades de Laravel 7"-](/blog/0021-novedades-de-laravel-7) dedicados a este tema.
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
extends: _layouts.post
section: content
title: "Novedades de Laravel 7: Cliente HTTP"
date: 2020-02-28
description: "Como en cada nueva versión, Laravel 7 nos trae una serie de nuevas funciones y mejoras. En este artículo destacaremos la integración de Laravel con Zttp bajo el nuevo facade HTTP."
cover_image: /assets/images/posts/0023/0023-novedades-de-laravel-7-el-nuevo-facade-http-consultas-nativas-a-servicios-externos.png
featured: false
categories: [laravel, php, programming]
---

Como en cada nueva versión, Laravel 7 nos trae una serie de nuevas funciones y mejoras. En este artículo destacaremos la integración de Laravel con [Zttp](https://github.com/kitetail/zttp) -que a su vez es un wrapper de [Guzzle](https://github.com/guzzle/guzzle)- bajo el nuevo _facade_ **HTTP**.

------

Este artículo pertenece a la serie [Novedades de Laravel 7](/blog/0021-novedades-de-laravel-7). Puedes leer sobre el resto de las características introducidas en esta versión [aquí](/blog/0021-novedades-de-laravel-7).

-----

Esta nueva fachada **HTTP** no es nada más que un wrapper de la popular librería **Guzzle**, con una API más familiar e intuitiva. Ofrece también, una manera fácil de aplicarla en nuestras pruebas unitarias y de integración.

### Haciendo requests

Escribir una llamada hacia un endpoint exterior es tan simple como:

use Illuminate\Support\Facades\Http;

$response = Http::get('http://la-url-del-servicio.com');

Este método retornará una instancia de ``Illuminate\Http\Client\Response`` la cual proveerá una serie de métodos que te permitirán inspeccionar la respuesta.

$response->body() : string;
$response->json() : array;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;

Esta clase también implementa la interfaz ``ArrayAccess``, por lo que puedes acceder a la data de la respuesta JSON directamente desde la respuesta:

return Http::get('http://la-url-del-servicio.com/users/1')['phone_number'];
// ^^^^^^^^^^^^^^

Cuando requieras enviar cierta información adicional al momento de realizar consulta de tipo ``POST``, ``PUT``, ``PATCH``, puedes realizarlo fácilmente pasando data como segundo argumento:

$response = Http::post('http://la-url-del-servicio.com/users', [
'name' => 'Kenny',
'role' => 'Titán',
]);

> Con la misma facilidad, puedes explorar las opciones para hacer [Requests con data codificada en la Url](https://laravel.com/docs/master/http-client#request-data) y [Requests Multi-part](https://laravel.com/docs/master/http-client#request-data).
### Autenticación

El **_facade_ HTTP** también nos provee una manera cómoda de manejar la **autenticación de nuestras peticiones** cuando hagamos consultas a servicios externos. Para esto, tenemos disponible tres formas de autenticación: Básica, _Digest_ y mediante un _Bearer_ token.

// Basic auth
$response = Http::withBasicAuth('kennyhorna@gmail.com', 'mi-clave')->post(...);

// Digest auth
$response = Http::withDigestAuth('kennyhorna@gmail.com', 'mi-clave')->post(...);

// Mediante un token
$response = Http::withToken('mi-token')->post(...);

### Cabeceras

Del mismo modo, podemos añadir cabeceras de esta forma:

$response = Http::withHeaders([
'X-una-cabecera' => 'valor-1',
'X-otra-cabecera' => 'valor-2'
])->post('http://la-url-del-servicio.com/users', [
'name' => 'Lilly Collins',
]);

### Manejo de errores

Una de las principales diferencias del uso del **_facade_ HTTP** y de Guzzle es que este último arroja una excepción si es que algo anda mal (errores ``4XX`` y ``5XX``). HTTP no lo hará por defecto, sino que te ofrece distintas formas de tratar los errores dependiendo de cómo quieras manejarlos. De este modo, podemos **consultar** a la respuesta de nuestra petición si es que todo marchó bien o si es que hubo algún error:

// Determina si el código de respuesta es >= 200 y < 300...
$response->successful();

// Determina si el código de respuesta es de nivel 400...
$response->clientError();

// Determina si el código de respuesta es de nivel 500...
$response->serverError();

Si lo que prefieres es que se arroje una **excepción** (instancia de ``Illuminate\Http\Client\RequestException``), puedes realizar lo siguiente:

$response = Http::post(...);

// Arrojar una excepción si es que hubo algún error..
$response->throw();

return $response['data'];

> Puedes leer más sobre el manejo de errores en [esta](https://laravel.com/docs/master/http-client#error-handling) sección de la documentación.
### Pruebas

Al igual que muchas funcionalidades de Laravel, esta no es la excepción. El **facade HTTP** nos permite **simular** estas peticiones externas y retornar **fake data**, para que podamos correr nuestras pruebas sin necesidad de realizar peticiones externas.

Para falsear una petición y respuesta, solo necesitamos invocar al método ``fake()`` antes de la lógica de nuestra prueba:

use Illuminate\Support\Facades\Http;

Http::fake();

$response = Http::post(...);

Si es que necesitamos simular peticione a distintos servicios -los cuales deberían retornar distinta data- podemos indicarlo pasando un arreglo de elementos a este método ``fake``:

Http::fake([
// Falseamos peticiones hacia endpoints de Facebook...
'facebook.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

// Falseamos peticiones hacia endpoints de Twitter...
'twitter.com/*' => Http::response('Hello World', 200, ['Headers']),
]);

> Puedes leer más sobre la **simulación de peticiones** [en esta sección](https://laravel.com/docs/master/http-client#faking-responses) de la documentación.
#### Inspeccionando respuestas

Si lo que necesitas es **asegurarte** de que estás enviando toda la información necesaria y adecuada en tus peticiones, puedes realizar estas validaciones mediante el método ``assetSent(...)`` (luego de haber invocado ``fake()``). Veamos un ejemplo.

// Activando la simulación de peticiones..
Http::fake();

// Realizando nuestra consulta..
Http::withHeaders([
'X-First' => 'foo',
])->post('http://la-url-del-servicio.com/users', [
'name' => 'Kenny',
'role' => 'author',
]);

// Verificando que se envió la data correcta..
Http::assertSent(function ($request) {
return $request->hasHeader('X-First', 'foo') &&
$request->url() == 'http://la-url-del-servicio.com/users' &&
$request['name'] == 'Kenny' &&
$request['role'] == 'author';
});


-----

## Cierre

La introducción del soporte de **peticiones HTTP** de manera **nativa** (si bien sea mediante un _wrapper_ de una de las librerías más utilizadas para estas tareas) hace más robusto aún a Laravel. Definitivamente la implementaré en mis proyectos, pues me atrae sobretodo la manera fácil de poder **integrarla a mis pruebas de software**. Ya ahondaremos en esto en una **futura serie dedicada a esta interesante práctica** ;).

Si te interesó esta nueva funcionalidad, no olvides leer **el resto de novedades que trae Laravel 7** ([aquí](/blog/0021-novedades-de-laravel-7)), ya que tenemos [una serie de artículos -"Novedades de Laravel 7"-](/blog/0021-novedades-de-laravel-7) dedicados a este tema.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5172132

Please sign in to comment.