Imagen del artículo

Valida y construye DTOs de forma dinamica con esta libreria

Escrito por Federico Juretich en Herramientas

Anteriormente vimos la importancia de los DTOs en un sistema. Ahora veremos cómo podemos crearlos de forma dinamica y rápida.

Construir DTOs al comienzo puede ser una tarea simple, fácil e incluso divertida. Pero, eso es solo al comienzo. Luego de que hayas construido varios DTOs y tengas que hacer más, te darás cuenta lo repetitivo que es e incluso hace sentirte que "pierdes" tiempo construyéndolos y validándolos.

Es por eso, que construí una librería que se encarga de validarlos y construirlos de forma dinámica. Mediante el uso de los attributes de PHP introducidos en la versión 8.0.

Dto Builder

Así le puse a esta librería. Te dejo el enlace al repositorio de Github: https://github.com/fedejuret/dto-builder

¿Cómo funciona esta librería? Es muy simple.

Pero primero, veamos cómo hariamos un DTO de forma tradicional.

class User {
        
    private int $id;
    private string $name;
    private string $email;
    private string $password;
    
    public function getId(): int {
        return $this->id;
    }
    
    public function setId(string $id): self {
        $this->id = $id;
        return $this;
    }
    
    ... todos los otros getters y setters
}

De esta forma estaríamos llenando las propiedades con los valores que necesitemos. Claramente, tendríamos que ir llamando setter por setter asignándole el valor. Lo mismo con las validaciones, ¿cómo me aseguro que $email realmente sea un email?, eso sería tarea del DTO también (o del consumidor del dto, es decir, quien lo buildea).

¿Cuál es el problema con la forma tradicional?

No hay problema como tal, y puedes seguir haciendolo de esa forma si lo prefieres.

¿Entonces?

Lo que aporta esta libreria es: optimizacion de tiempos y segregacion de responsabilidades.

Al usarla, estamos construyendo y validando dtos de forma mucho mas rapida. Y, las validaciones, pasan a ser responsabilidad de otra parte de mi sistema, y no mía como desarrollador.

Cómo generar DTOs con la librería

Primero tenemos que instalar la librería en nuestro proyecto usando composer.

Para ello ejecutamos:

composer require fedejuret/dto-builder

Una vez instalada, entonces continuamos usando el ejemplo anterior:

class User {
    
    use Loadable;

    #[Property]
    #[Required]
    #[IsNumber]
    private int $id;
    
    #[Property]
    #[Required]
    #[IsString]
    #[Length(min: 4, max: 50)]
    private string $name;
    
    #[Property]
    #[Required]
    #[IsEmail]
    private string $email;
    
    #[Property]
    #[IsRegex(pattern: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/')]
    private string $password;
    
    public function getId(): int {
        return $this->id;
    }
    
    ... todos los otros getters
}

Bien, ahora hablemos de las diferencias entre este código y el anterior.

Ahora voy a explicar qué es cada uno de estos puntos mencionados anteriormente.

Atributos

Los atributos en que se encuentran arriba de las propiedades son de dos tipos:

¿Cuántas validaciones hay? De momento existen todas las que puedes encontrar en este link: https://github.com/fedejuret/dto-builder/tree/master/src/Attributes/Validations

Traits: Loadable & Arrayable

El trait Loadable es quien se encarga de construir el DTO de forma dinámica. ¿Cómo lo hace? Mediante el método loadFromArray. Veamos un ejemplo:


$dto = (new User())->loadFromArray([
    'id' => 1,
    'name' => 'Federico Juretich',
    'email' => '[email protected]',
    'password' => 'SomeSecureP45W07D@'
]);

De esta manera, estoy mapeando cada índice del array con una propiedad de mí DTO. Pero, previamente a que se haga la asignación, se corren todas las validaciones que cada propiedad tiene. Entonces, si, por ejemplo, no me envían un email con formato válido, el programa lanza una excepción del tipo ValidationException

Y de esta forma sencilla, de un array que podría ser una query a la base de datos, una request, un comando, o cualquier cosa de uso que se imaginen, estoy validando y contruyendo un DTO.


El trait Arrayable lo que hace, es habilitar un método al DTO que es toArray, esto sirve para convertir el objeto User al array original.

Validaciones Custom

La librería permite que cada desarrollador cree sus propias validaciones. Para ello, veamos un ejemplo de cómo hay que hacer.-

use Attribute;
use Fedejuret\DtoBuilder\Interfaces\ValidationInterface;

#[Attribute(Attribute::TARGET_PROPERTY)]
class IsSecurePassword implements ValidationInterface {
    
    	public function validate(ReflectionProperty $property, mixed $value): void
    	{
    		if (preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/', $value) !== 1) {
    			throw new CustomException(); // La contraseña no es segura
    		}
    	}

}

De esta forma, ahora podremos usar el atributo IsSecurePassword sobre la propiedad que queremos validar. Y la librería automáticamente ejecutará la lógica dentro del método validate.

php clean code dtos
Articulos relacionados
Imagen de artículo

Data Transfer Objects (DTOs): Qué son y por qué son importantes

En el desarrollo de software, es fundamental manejar de manera organizada los datos que fluyen entre distintas partes del sistema. Aquí es donde entran en juego los Data Transfer Objects (DTOs). En este artículo, exploraremos qué son los DTOs, por qué son importantes y en qué situaciones pueden ser útiles.

Imagen de artículo

¿Vale la pena comprar la licencia de PhpStorm?

En este artículo, exploraremos las características más destacadas de PhpStorm, sus ventajas frente a otras opciones y, sobre todo, si la inversión en su licencia está justificada.

Imagen de artículo

PHP: De scripts básicos a un lenguaje poderoso y moderno

PHP nació en 1995 como una solución sencilla para construir páginas web dinámicas. En un mundo dominado por CGI y Perl, PHP ofreció una alternativa fácil de aprender y desplegar, diseñada específicamente para el entorno web. Sin embargo, lo que comenzó como una herramienta básica, evolucionó hacia un lenguaje robusto, capaz de competir con gigantes como Python, Ruby y JavaScript.