Validación
Livewire tiene como objetivo hacer que la validación de la entrada de un usuario y darle retroalimentación sea lo más agradable posible. Al construir sobre las características de validación de Laravel, Livewire aprovecha su conocimiento existente mientras que también le proporciona características robustas y adicionales como la validación en tiempo real.
Aquí hay un ejemplo de componente CreatePost que demuestra el flujo de trabajo de validación más básico en Livewire:
<?php
namespace App\Livewire;
use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ public $title = '';
public $content = '';
public function save() { $validated = $this->validate([ 'title' => 'required|min:3', 'content' => 'required|min:3', ]);
Post::create($validated);
return redirect()->to('/posts'); }
public function render() { return view('livewire.create-post'); }}<form wire:submit="save"> <input type="text" wire:model="title"> <div>@error('title') {{ $message }} @enderror</div>
<textarea wire:model="content"></textarea> <div>@error('content') {{ $message }} @enderror</div>
<button type="submit">Save</button></form>Como puede ver, Livewire proporciona un método validate() que puede llamar para validar las propiedades de su componente. Devuelve el conjunto de datos validados que puedes insertar de forma segura en la base de datos.
En el frontend, puedes utilizar las directivas Blade existentes en Laravel para mostrar mensajes de validación a tus usuarios.
Para obtener más información, consulte la documentación de Laravel sobre la representación de errores de validación en Blade.
Atributos de validación
Si prefiere co-localizar las reglas de validación de su componente con las propiedades directamente, puede utilizar el atributo #[Validate] de Livewire.
Al asociar las reglas de validación con las propiedades utilizando #[Validate], Livewire ejecutará automáticamente las reglas de validación de las propiedades antes de cada actualización. Sin embargo, aún debe ejecutar $this->validate() antes de persistir los datos a una base de datos para que las propiedades que no han sido actualizadas también sean validadas.
<?php
namespace App\Livewire;
use Livewire\Attributes\Validate;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ #[Validate('required|min:3')] public $title = '';
#[Validate('required|min:3')] public $content = '';
public function save() { $this->validate();
Post::create([ 'title' => $this->title, 'content' => $this->content, ]);
return redirect()->to('/posts'); }
// ...}Si prefieres tener más control sobre cuándo se validan las propiedades, puedes pasar un parámetro onUpdate: false al atributo #[Validate]. Esto desactivará cualquier validación automática y en su lugar asumirá que quieres validar manualmente las propiedades usando el método $this->validate():
<?php
namespace App\Livewire;
use Livewire\Attributes\Validate;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ #[Validate('required|min:3', onUpdate: false)] public $title = '';
#[Validate('required|min:3', onUpdate: false)] public $content = '';
public function save() { $validated = $this->validate();
Post::create($validated);
return redirect()->to('/posts'); }
// ...}Personalización del nombre del atributo
Si desea personalizar el nombre del atributo inyectado en el mensaje de validación, puede hacerlo utilizando el parámetro as::
use Livewire\Attributes\Validate;
#[Validate('required', as: 'fecha de nacimiento')]public $fdn;Cuando la validación falla en el fragmento anterior, Laravel utilizará “fecha de nacimiento” en lugar de “fdn” como nombre del campo en el mensaje de validación. El mensaje generado será “The fecha de nacimiento field is required” en lugar de “The fdn field is required”.
Mensaje de validación personalizado
Para omitir el mensaje de validación de Laravel y sustituirlo por el tuyo propio, puedes utilizar el parámetro message: en el atributo #[Validate]:
use Livewire\Attributes\Validate;
#[Validate('required', message: 'Por favor, proporcione un título de entrada')]public $title;Ahora, cuando la validación falle para esta propiedad, el mensaje será “Por favor, proporcione un título de entrada” en lugar de “The title field is required”.
Si desea añadir diferentes mensajes para diferentes reglas, puede simplemente proporcionar múltiples atributos #[Validate]:
#[Validate('required', message: 'Por favor, proporcione un título de entrada')]#[Validate('min:3', message: 'El título es demasiado corto')]public $title;Exclusión de la localización
Por defecto, los mensajes y atributos de las reglas Livewire se localizan usando el ayudante de traducción de Laravel: trans().
Puedes desactivar la localización pasando el parámetro translate: false al atributo #[Validate]:
#[Validate('required', message: 'Por favor, proporcione un título de entrada', translate: false)]public $title;Clave personalizada
Cuando se aplican reglas de validación directamente a una propiedad utilizando el atributo #[Validate], Livewire asume que la clave de validación debe ser el nombre de la propia propiedad. Sin embargo, hay ocasiones en las que puede querer personalizar la clave de validación.
Por ejemplo, puede que desee proporcionar reglas de validación separadas para una propiedad de matriz y sus hijos. En este caso, en lugar de pasar una regla de validación como primer argumento al atributo #[Validate], puedes pasar un array de pares clave-valor:
#[Validate([ 'todos' => 'required', 'todos.*' => [ 'required', 'min:3', new Uppercase, ],])]public $todos = [];Ahora, cuando un usuario actualice $todos, o se llame al método validate(), se aplicarán ambas reglas de validación.
Objetos de formulario
A medida que se añaden más propiedades y reglas de validación a un componente Livewire, puede empezar a sentirse demasiado abarrotado. Para aliviar este dolor y también proporcionar una abstracción útil para la reutilización de código, puede utilizar los Objetos Formulario de Livewire para almacenar sus propiedades y reglas de validación.
A continuación se muestra el mismo ejemplo CreatePost, pero ahora las propiedades y reglas se han extraído a un objeto de formulario dedicado llamado PostForm:
<?php
namespace App\Livewire\Forms;
use Livewire\Attributes\Validate;use Livewire\Form;
class PostForm extends Form{ #[Validate('required|min:3')] public $title = '';
#[Validate('required|min:3')] public $content = '';}El PostForm anterior puede definirse ahora como una propiedad del componente CreatePost:
<?php
namespace App\Livewire;
use App\Livewire\Forms\PostForm;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ public PostForm $form;
public function save() { Post::create( $this->form->all() );
return redirect()->to('/posts'); }
// ...}Como puedes ver, en lugar de listar cada propiedad individualmente, podemos recuperar todos los valores de las propiedades usando el método ->all() en el objeto form.
Además, al hacer referencia a los nombres de las propiedades en la plantilla, debe anteponer form. a cada instancia:
<form wire:submit="save"> <input type="text" wire:model="form.title"> <div>@error('form.title') {{ $message }} @enderror</div>
<textarea wire:model="form.content"></textarea> <div>@error('form.content') {{ $message }} @enderror</div>
<button type="submit">Save</button></form>Cuando se utilizan objetos formulario, la validación del atributo #[Validate] se ejecutará cada vez que se actualice una propiedad. Sin embargo, si desactiva este comportamiento especificando onUpdate: false en el atributo, puede ejecutar manualmente la validación de un objeto formulario utilizando $this->form->validate():
public function save(){ Post::create( $this->form->validate() );
return redirect()->to('/posts');}Los objetos de formulario son una abstracción útil para la mayoría de los conjuntos de datos más grandes y una variedad de características adicionales que los hacen aún más potentes. Para más información,consulte la completa documentación sobre objetos formulario.
Validación en tiempo real (Real-time validation)
Validación en tiempo real es el término que se utiliza cuando se valida la entrada de un usuario mientras rellena un formulario en lugar de esperar al envío del formulario.
Al utilizar atributos #[Validate] directamente en las propiedades Livewire, cada vez que se envíe una solicitud de red para actualizar el valor de una propiedad en el servidor, se aplicarán las reglas de validación proporcionadas.
Esto significa que para proporcionar una experiencia de validación en tiempo real para sus usuarios en una entrada específica, no se requiere ningún trabajo adicional de backend. Lo único que se requiere es utilizar wire:model.live o wire:model.blur para indicar a Livewire que active solicitudes de red a medida que se rellenan los campos.
En el siguiente ejemplo, se ha añadido wire:model.blur a la entrada de texto. Ahora, cuando un usuario escriba en el campo y luego haga tabulador o clic fuera del campo, se disparará una petición de red con el valor actualizado y se ejecutarán las reglas de validación:
<form wire:submit="save"> <input type="text" wire:model.blur="title">
<!-- --></form>Si utilizas un método rules() para declarar las reglas de validación de una propiedad en lugar del atributo #[Validate], puedes incluir un atributo #[Validate] sin parámetros para mantener el comportamiento de validación en tiempo real:
use Livewire\Attributes\Validate;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ #[Validate] public $title = '';
public $content = '';
protected function rules() { return [ 'title' => 'required|min:5', 'content' => 'required|min:5', ]; }
public function save() { $validated = $this->validate();
Post::create($validated);
return redirect()->to('/posts'); }Ahora, en el ejemplo anterior, aunque #[Validate] esté vacío, le dirá a Livewire que ejecute la validación de campos proporcionada por rules() cada vez que se actualice la propiedad.
Personalización de los mensajes de error
Laravel proporciona mensajes de validación como “El campo title es obligatorio” si la propiedad $title tiene la regla required asociada.
Sin embargo, puede que necesites personalizar el lenguaje de estos mensajes de error para adaptarlos mejor a tu aplicación y a sus usuarios.
Nombres de atributos personalizados
A veces la propiedad que está validando tiene un nombre que no es adecuado para mostrar a los usuarios. Por ejemplo, si tiene un campo de base de datos en su aplicación llamado dob que significa “Fecha de nacimiento”, querría mostrar a sus usuarios “El campo de fecha de nacimiento es obligatorio” en lugar de “El campo dob es obligatorio”.
Livewire le permite especificar un nombre alternativo para una propiedad utilizando el parámetro as::
use Livewire\Attributes\Validate;
#[Validate('required', as: 'fecha de nacimiento')]public $dob = '';Ahora, si la regla de validación required falla, el mensaje de error dirá ""l campo de fecha de nacimiento es requerido.” en lugar de “El campo dob es requerido.”.
Mensajes personalizados
Si personalizar el nombre de la propiedad no es suficiente, puede personalizar todo el mensaje de validación utilizando el parámetro message::
use Livewire\Attributes\Validate;
#[Validate('required', message: 'Por favor, rellene su fecha de nacimiento.')]public $dob = '';Si tiene varias reglas para las que personalizar el mensaje, se recomienda que utilice atributos #[Validate] completamente separados para cada una, como se muestra a continuación:
use Livewire\Attributes\Validate;
#[Validate('required', message: 'Por favor, introduzca un título.')]#[Validate('min:5', message: 'Su título es demasiado corto.')]public $title = '';Si prefieres utilizar la sintaxis de array del atributo #[Validate], puedes especificar atributos y mensajes personalizados de la siguiente forma:
use Livewire\Attributes\Validate;
#[Validate([ 'titles' => 'required', 'titles.*' => 'required|min:5',], mensaje: [ 'required' => 'Falta el atributo :.', 'titles.required' => 'Faltan los :atributos', 'min' => 'El atributo :es demasiado corto',], attribute: [ 'titles.*' => 'title',])]public $titles = [];Definir un método rules()
Como alternativa a los atributos #[Validate] de Livewire, puedes definir un método en tu componente llamado rules() y devolver una lista de campos y sus correspondientes reglas de validación. Esto puede ser útil si está intentando utilizar sintaxis en tiempo de ejecución que no están soportadas en los Atributos PHP, por ejemplo, objetos rule Laravel como Rule::password().
Estas reglas se aplicarán cuando ejecute $this->validate() dentro del componente. También puedes definir las funciones messages() y validationAttributes().
He aquí un ejemplo:
use Livewire\Component;use App\Models\Post;use Illuminate\Validation\Rule;
class CreatePost extends Component{ public $title = '';
public $content = '';
protected function rules() { return [ 'title' => Rule::exists('posts', 'title'), 'content' => 'required|min:3', ]; }
protected function messages() { return [ 'content.required' => 'Falta el campo :attribute.', 'content.min' => 'El campo :attribute es demasiado corto.', ]; }
protected function validationAttributes() { return [ 'content' => 'description', ]; }
public function save() { $this->validate();
Post::create([ 'title' => $this->title, 'content' => $this->content, ]);
return redirect()->to('/posts'); }
// ...}Uso de objetos Laravel Rule
Los objetos Rule de Laravel son una forma extremadamente potente de añadir comportamientos avanzados de validación a tus formularios.
He aquí un ejemplo de uso de objetos Rule junto con el método rules() de Livewire para conseguir una validación más sofisticada:
<?php
namespace App\Livewire;
use Illuminate\Validation\Rule;use App\Models\Post;use Livewire\Form;
class UpdatePost extends Form{ public ?Post $post;
public $title = '';
public $content = '';
protected function rules() { return [ 'title' => [ 'required', Rule::unique('posts')->ignore($this->post), ], 'content' => 'required|min:5', ]; }
public function mount() { $this->title = $this->post->title; $this->content = $this->post->content; }
public function update() { $this->validate();
$this->post->update($this->all());
$this->reset(); }
// ...}Control manual de los errores de validación
Las utilidades de validación de Livewire deberían manejar los escenarios de validación más comunes; sin embargo, hay ocasiones en las que puede querer un control total sobre los mensajes de validación en su componente.
A continuación se muestran todos los métodos disponibles para manipular los errores de validación en su componente Livewire:
| Método | Descripción |
|---|---|
$this->addError([key], [message]) | Añadir manualmente un mensaje de validación a la bolsa de errores |
$this->resetValidation([?key]) | Restablecer los errores de validación para la clave proporcionada, o restablecer todos los errores si no se proporciona ninguna clave. |
$this->getErrorBag() | Recupera la bolsa de errores subyacente de Laravel utilizada en el componente Livewire |
Acceso a la instancia del validador
A veces puedes querer acceder a la instancia del validador que Livewire utiliza internamente en el método validate(). Esto es posible utilizando el método withValidator. El cierre que proporcionas recibe el validador completamente construido como argumento, permitiéndote llamar a cualquiera de sus métodos antes de que las reglas de validación sean realmente evaluadas.
A continuación se muestra un ejemplo de intercepción del validador interno de Livewire para comprobar manualmente una condición y añadir un mensaje de validación adicional:
use Livewire\Attributes\Validate;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ #[Validate('required|min:3')] public $title = '';
#[Validate('required|min:3')] public $content = '';
public function boot() { $this->withValidator(function ($validator) { $validator->after(function ($validator) { if (str($this->title)->startsWith('"')) { $validator->errors()->add('title', 'El título no puede empezar con con "'); } }); }); }
public function save() { Post::create($this->all());
return redirect()->to('/posts'); }
// ...}Uso de validadores personalizados
Si desea utilizar su propio sistema de validación en Livewire, no hay ningún problema. Livewire capturará cualquier excepción ValidationException lanzada dentro de los componentes y proporcionará los errores a la vista como si estuvieras usando el propio método validate() de Livewire.
A continuación se muestra un ejemplo del componente CreatePost, pero en lugar de utilizar las características de validación de Livewire, se está creando un validador completamente personalizado y se aplica a las propiedades del componente:
use Illuminate\Support\Facades\Validator;use Livewire\Component;use App\Models\Post;
class CreatePost extends Component{ public $title = '';
public $content = '';
public function save() { $validated = Validator::make( // Datos que vamos a validar ['title' => $this->title, 'content' => $this->content],
// Reglas de validación que aplicaremos ['title' => 'required|min:3', 'content' => 'required|min:3'],
// Mensajes de validación personalizados ['required' => 'El campo :attribute field es obligatorio'], )->validate();
Post::create($validated);
return redirect()->to('/posts'); }
// ...}Pruebas de validación
Livewire proporciona útiles utilidades de prueba para escenarios de validación, como el método assertHasErrors().
A continuación se muestra un caso de prueba básico que asegura que se lanzan errores de validación si no se establece ninguna entrada para la propiedad title:
<?php
namespace Tests\Feature\Livewire;
use App\Livewire\CreatePost;use Livewire\Livewire;use Tests\TestCase;
class CreatePostTest extends TestCase{ /** @test */ public function cant_create_post_without_title() { Livewire::test(CreatePost::class) ->set('content', 'Contenido de ejemplo...') ->call('save') ->assertHasErrors('title'); }}Además de comprobar la presencia de errores, assertHasErrors también permite limitar la comprobación a reglas específicas pasando las reglas que se deben comprobar como segundo argumento del método:
/** @test */public function cant_create_post_with_title_shorter_than_3_characters(){ Livewire::test(CreatePost::class) ->set('title', 'ti') ->set('content', 'Contenido de ejemplo...') ->call('save') ->assertHasErrors(['title' => ['min:3']]);}También puede afirmar la presencia de errores de validación para múltiples propiedades al mismo tiempo:
/** @test */public function cant_create_post_without_title_and_content(){ Livewire::test(CreatePost::class) ->call('save') ->assertHasErrors(['title', 'content']);}Para más información sobre otras utilidades de prueba proporcionadas por Livewire, consulte la documentación de testing.
Atributo [#Rule] obsoleto (deprecated)
Cuando Livewire v3 se lanzó por primera vez, utilizaba el término “Rule” en lugar de “Validate” para sus atributos de validación (#[Rule]).
Debido a conflictos de nomenclatura con los objetos de regla de Laravel, esto se ha cambiado desde entonces a #[Validate]. Ambos son compatibles con Livewire v3, sin embargo, se recomienda que cambie todas las apariciones de #[Rule] con #[Validate] para mantenerse al día.