1. Paquetes
  2. Precognition

Introducción

Laravel Precognition le permite anticipar el resultado de una solicitud HTTP futura. Uno de los casos de uso principales de Precognition es la capacidad de proporcionar validación "en vivo" para su aplicación JavaScript frontend sin tener que duplicar las reglas de validación del backend de su aplicación. Precognition se combina especialmente bien con los kits de inicio de Laravel basados en Inertia.

Cuando Laravel recibe una "solicitud precognitiva", ejecutará todos los middleware de la ruta y resolverá las dependencias del controlador de la ruta, incluida la validación de solicitudes de formularios - pero no ejecutará realmente el método del controlador de la ruta.

Validación en vivo

Uso de Vue

Usando Laravel Precognition, puede ofrecer experiencias de validación en vivo a sus usuarios sin tener que duplicar sus reglas de validación en su aplicación frontend Vue. Para ilustrar cómo funciona, construyamos un formulario para crear nuevos usuarios en nuestra aplicación.

Primero, para habilitar Precognition para una ruta, debe agregar el middleware HandlePrecognitiveRequests a la definición de la ruta. También debe crear una solicitud de formulario para almacenar las reglas de validación de la ruta:

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
 
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);

Luego, debe instalar los ayudantes de frontend de Laravel Precognition para Vue a través de NPM:

npm install laravel-precognition-vue

Con el paquete Laravel Precognition instalado, ahora puede crear un objeto de formulario usando la función useForm de Precognition, proporcionando el método HTTP (post), la URL de destino (/users) y los datos iniciales del formulario.

Luego, para habilitar la validación en vivo, invoque el método validate del formulario en el evento change de cada entrada, proporcionando el nombre de la entrada:

<script setup>
import { useForm } from 'laravel-precognition-vue';
 
const form = useForm('post', '/users', {
name: '',
email: '',
});
 
const submit = () => form.submit();
</script>
 
<template>
<form @submit.prevent="submit">
<label for="name">Name</label>
<input
id="name"
v-model="form.name"
@change="form.validate('name')"
/>
<div v-if="form.invalid('name')">
{{ form.errors.name }}
</div>
 
<label for="email">Email</label>
<input
id="email"
type="email"
v-model="form.email"
@change="form.validate('email')"
/>
<div v-if="form.invalid('email')">
{{ form.errors.email }}
</div>
 
<button :disabled="form.processing">
Create User
</button>
</form>
</template>

Ahora, a medida que el usuario llena el formulario, Precognition proporcionará una salida de validación en vivo basada en las reglas de validación en la solicitud de formulario de la ruta. Cuando se cambian las entradas del formulario, se enviará una solicitud de validación "precognitiva" con retardo a su aplicación Laravel. Puede configurar el tiempo de espera de retardo llamando a la función setValidationTimeout del formulario:

form.setValidationTimeout(3000);

Cuando una solicitud de validación está en curso, la propiedad validating del formulario será true:

<div v-if="form.validating">
Validating...
</div>

Cualquier error de validación devuelto durante una solicitud de validación o el envío de un formulario se llenará automáticamente en el objeto errors del formulario:

<div v-if="form.invalid('email')">
{{ form.errors.email }}
</div>

Puede determinar si el formulario tiene errores utilizando la propiedad hasErrors del formulario:

<div v-if="form.hasErrors">
<!-- ... -->
</div>

También puede determinar si una entrada ha pasado o fallado la validación pasando el nombre de la entrada a las funciones valid e invalid del formulario, respectivamente:

<span v-if="form.valid('email')">
</span>
 
<span v-else-if="form.invalid('email')">
</span>

Advertencia Una entrada de formulario solo aparecerá como válida o no válida una vez que haya cambiado y se haya recibido una respuesta de validación.

Si está validando un subconjunto de las entradas de un formulario con Precognition, puede ser útil borrar errores manualmente. Puede utilizar la función forgetError del formulario para lograr esto:

<input
id="avatar"
type="file"
@change="(e) => {
form.avatar = e.target.files[0]
 
form.forgetError('avatar')
}"
>

Por supuesto, también puede ejecutar código en reacción a la respuesta al envío del formulario. La función submit del formulario devuelve una promesa de solicitud Axios. Esto proporciona una manera conveniente de acceder a la carga de respuesta, restablecer las entradas del formulario en caso de un envío exitoso o manejar una solicitud fallida:

const submit = () => form.submit()
.then(response => {
form.reset();
 
alert('User created.');
})
.catch(error => {
alert('An error occurred.');
});

Puede determinar si una solicitud de envío de formulario está en curso inspeccionando la propiedad processing del formulario:

<button :disabled="form.processing">
Submit
</button>

Uso de Vue y Inertia

Nota Si desea comenzar con ventaja al desarrollar su aplicación Laravel con Vue e Inertia, considere utilizar uno de nuestros kits de inicio. Los kits de inicio de Laravel proporcionan un andamiaje de autenticación tanto en el backend como en el frontend para su nueva aplicación Laravel.

Antes de usar Precognition con Vue e Inertia, asegúrese de revisar nuestra documentación general sobre el uso de Precognition con Vue. Al usar Vue con Inertia, deberá instalar la biblioteca Precognition compatible con Inertia a través de NPM:

npm install laravel-precognition-vue-inertia

Una vez instalada, la función useForm de Precognition devolverá un ayudante de formulario de Inertia con las funciones de validación discutidas anteriormente.

El método submit del ayudante de formulario se ha simplificado, eliminando la necesidad de especificar el método HTTP o la URL. En su lugar, puede pasar las opciones de visita de Inertia como el primer y único argumento. Además, el método submit no devuelve una Promesa como se ve en el ejemplo de Vue anterior. En su lugar, puede proporcionar cualquiera de los retrocesos de eventos admitidos por Inertia en las opciones de visita dadas al método submit:

<script setup>
import { useForm } from 'laravel-precognition-vue-inertia';
 
const form = useForm('post', '/users', {
name: '',
email: '',
});
 
const submit = () => form.submit({
preserveScroll: true,
onSuccess: () => form.reset(),
});
</script>

Uso de React

Usando Laravel Precognition, puede ofrecer experiencias de validación en vivo a sus usuarios sin tener que duplicar las reglas de validación en su aplicación frontend React. Para ilustrar cómo funciona, construyamos un formulario para crear nuevos usuarios en nuestra aplicación.

Primero, para habilitar Precognition para una ruta, debe agregar el middleware HandlePrecognitiveRequests a la definición de la ruta. También debe crear una solicitud de formulario para almacenar las reglas de validación de la ruta:

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
 
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);

Luego, debe instalar los ayudantes de frontend de Laravel Precognition para React a través de NPM:

npm install laravel-precognition-react

Con el paquete Laravel Precognition instalado, ahora puede crear un objeto de formulario usando la función useForm de Precognition, proporcionando el método HTTP (post), la URL de destino (/users), y los datos iniciales del formulario.

Para habilitar la validación en vivo, debe escuchar los eventos change y blur de cada entrada. En el controlador de eventos change, debe establecer los datos del formulario con la función setData, pasando el nombre de la entrada y el nuevo valor. Luego, en el controlador de eventos blur, invoque el método validate del formulario, proporcionando el nombre de la entrada:

import { useForm } from 'laravel-precognition-react';
 
export default function Form() {
const form = useForm('post', '/users', {
name: '',
email: '',
});
 
const submit = (e) => {
e.preventDefault();
 
form.submit();
};
 
return (
<form onSubmit={submit}>
<label for="name">Name</label>
<input
id="name"
value={form.data.name}
onChange={(e) => form.setData('name', e.target.value)}
onBlur={() => form.validate('name')}
/>
{form.invalid('name') && <div>{form.errors.name}</div>}
 
<label for="email">Email</label>
<input
id="email"
value={form.data.email}
onChange={(e) => form.setData('email', e.target.value)}
onBlur={() => form.validate('email')}
/>
{form.invalid('email') && <div>{form.errors.email}</div>}
 
<button disabled={form.processing}>
Create User
</button>
</form>
);
};

Ahora, a medida que el usuario llena el formulario, Precognition proporcionará una salida de validación en vivo basada en las reglas de validación en la solicitud de formulario de la ruta. Cuando se cambian las entradas del formulario, se enviará una solicitud de validación "precognitiva" con retardo a su aplicación Laravel. Puede configurar el tiempo de espera de retardo llamando a la función setValidationTimeout del formulario:

form.setValidationTimeout(3000);

Cuando una solicitud de validación está en curso, la propiedad validating del formulario será true:

{form.validating && <div>Validating...</div>}

Cualquier error de validación devuelto durante una solicitud de validación o el envío de un formulario se llenará automáticamente en el objeto errors del formulario:

{form.invalid('email') && <div>{form.errors.email}</div>}

Puede determinar si el formulario tiene errores utilizando la propiedad hasErrors del formulario:

{form.hasErrors && <div><!-- ... --></div>}

También puede determinar si una entrada ha pasado o fallado la validación pasando el nombre de la entrada a las funciones valid e invalid del formulario, respectivamente:

{form.valid('email') && <span></span>}
 
{form.invalid('email') && <span></span>}

Advertencia Una entrada de formulario solo aparecerá como válida o no válida una vez que haya cambiado y se haya recibido una respuesta de validación.

Si está validando un subconjunto de las entradas de un formulario con Precognition, puede ser útil borrar errores manualmente. Puede utilizar la función forgetError del formulario para lograr esto:

<input
id="avatar"
type="file"
onChange={(e) =>
form.setData('avatar', e.target.value);
 
form.forgetError('avatar');
}
>

Por supuesto, también puede ejecutar código en reacción a la respuesta al envío del formulario. La función submit del formulario devuelve una promesa de solicitud Axios. Esto proporciona una manera conveniente de acceder a la carga de respuesta, restablecer las entradas del formulario en caso de un envío exitoso o manejar una solicitud fallida:

const submit = (e) => {
e.preventDefault();
 
form.submit()
.then(response => {
form.reset();
 
alert('User created.');
})
.catch(error => {
alert('An error occurred.');
});
};

Puede determinar si una solicitud de envío de formulario está en curso inspeccionando la propiedad processing del formulario:

<button disabled={form.processing}>
Submit
</button>

Uso de React y Inertia

Nota Si desea comenzar con ventaja al desarrollar su aplicación Laravel con React e Inertia, considere utilizar uno de nuestros kits de inicio. Los kits de inicio de Laravel proporcionan un andamiaje de autenticación tanto en el backend como en el frontend para su nueva aplicación Laravel.

Antes de usar Precognition con React e Inertia, asegúrese de revisar nuestra documentación general sobre el uso de Precognition con React. Al usar React con Inertia, deberá instalar la biblioteca compatible con Precognition de Inertia a través de NPM:

npm install laravel-precognition-react-inertia

Una vez instalada, la función useForm de Precognition devolverá un ayudante de formulario de Inertia mejorado con las funciones de validación discutidas anteriormente.

El método submit del ayudante de formulario se ha simplificado, eliminando la necesidad de especificar el método HTTP o la URL. En su lugar, puede pasar las opciones de visita de Inertia como el primer y único argumento. Además, el método submit no devuelve una Promesa como se ve en el ejemplo de React anterior. En su lugar, puede proporcionar cualquiera de los retrocesos de eventos admitidos por Inertia en las opciones de visita dadas al método submit:

import { useForm } from 'laravel-precognition-react-inertia';
 
const form = useForm('post', '/users', {
name: '',
email: '',
});
 
const submit = (e) => {
e.preventDefault();
 
form.submit({
preserveScroll: true,
onSuccess: () => form.reset(),
});
};

Uso de Alpine y Blade

Usando Laravel Precognition, puede ofrecer experiencias de validación en vivo a sus usuarios sin tener que duplicar las reglas de validación en su aplicación frontend Alpine. Para ilustrar cómo funciona, construyamos un formulario para crear nuevos usuarios en nuestra aplicación.

Primero, para habilitar Precognition para una ruta, debe agregar el middleware HandlePrecognitiveRequests a la definición de la ruta. También debe crear una solicitud de formulario para almacenar las reglas de validación de la ruta:

use App\Http\Requests\CreateUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
 
Route::post('/users', function (CreateUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);

Luego, debe instalar los ayudantes de frontend de Laravel Precognition para Alpine a través de NPM:

npm install laravel-precognition-alpine

Después, registre el complemento Precognition con Alpine en su archivo resources/js/app.js:

import Alpine from 'alpinejs';
import Precognition from 'laravel-precognition-alpine';
 
window.Alpine = Alpine;
 
Alpine.plugin(Precognition);
Alpine.start();

Con el paquete Laravel Precognition instalado y registrado, ahora puede crear un objeto de formulario usando la "magia" $form de Precognition, proporcionando el método HTTP (post), la URL de destino (/users) y los datos iniciales del formulario.

Para habilitar la validación en vivo, debe vincular los datos del formulario a su entrada relevante y luego escuchar el evento change de cada entrada. En el controlador de eventos change, debe invocar el método validate del formulario, proporcionando el nombre de la entrada:

<form x-data="{
form: $form('post', '/register', {
name: '',
email: '',
}),
}">
@csrf
<label for="name">Name</label>
<input
id="name"
name="name"
x-model="form.name"
@change="form.validate('name')"
/>
<template x-if="form.invalid('name')">
<div x-text="form.errors.name"></div>
</template>
 
<label for="email">Email</label>
<input
id="email"
name="email"
x-model="form.email"
@change="form.validate('email')"
/>
<template x-if="form.invalid('email')">
<div x-text="form.errors.email"></div>
</template>
 
<button :disabled="form.processing">
Create User
</button>
</form>

Ahora, a medida que el usuario llena el formulario, Precognition proporcionará una salida de validación en vivo basada en las reglas de validación en la solicitud de formulario de la ruta. Cuando se cambian las entradas del formulario, se enviará una solicitud de validación "precognitiva" con retardo a su aplicación Laravel. Puede configurar el tiempo de espera de retardo llamando a la función setValidationTimeout del formulario:

form.setValidationTimeout(3000);

Cuando una solicitud de validación está en curso, la propiedad validating del formulario será true:

<template x-if="form.validating">
<div>Validating...</div>
</template>

Cualquier error de validación devuelto durante una solicitud de validación o el envío de un formulario se llenará automáticamente en el objeto errors del formulario:

<template x-if="form.invalid('email')">
<div x-text="form.errors.email"></div>
</template>

Puede determinar si el formulario tiene algún error utilizando la propiedad hasErrors del formulario:

<template x-if="form.hasErrors">
<div><!-- ... --></div>
</template>

También puede determinar si una entrada ha pasado o fallado la validación pasando el nombre de la entrada a las funciones valid e invalid del formulario, respectivamente:

<template x-if="form.valid('email')">
<span></span>
</template>
 
<template x-if="form.invalid('email')">
<span></span>
</template>

Advertencia Una entrada de formulario solo aparecerá como válida o no válida una vez que haya cambiado y se haya recibido una respuesta de validación.

Puede determinar si una solicitud de envío de formulario está en curso inspeccionando la propiedad processing del formulario:

<button :disabled="form.processing">
Submit
</button>

Repopulación de datos de formularios antiguos

En el ejemplo de creación de usuarios discutido anteriormente, estamos utilizando Precognition para realizar validación en vivo; sin embargo, estamos realizando un envío tradicional del formulario al servidor para enviar el formulario. Por lo tanto, el formulario debería llenarse con cualquier entrada "antigua" y errores de validación devueltos desde el envío del formulario del lado del servidor:

<form x-data="{
form: $form('post', '/register', {
name: '{{ old('name') }}',
email: '{{ old('email') }}',
}).setErrors({{ Js::from($errors->messages()) }}),
}">

Alternativamente, si desea enviar el formulario a través de XHR, puede utilizar la función submit del formulario, que devuelve una promesa de solicitud Axios:

<form
x-data="{
form: $form('post', '/register', {
name: '',
email: '',
}),
submit() {
this.form.submit()
.then(response => {
form.reset();
 
alert('User created.')
})
.catch(error => {
alert('An error occurred.');
});
},
}"
@submit.prevent="submit"
>

Configuración de Axios

Las bibliotecas de validación de Precognition utilizan el cliente HTTP Axios para enviar solicitudes al backend de su aplicación. Para mayor comodidad, la instancia de Axios se puede personalizar si es necesario para su aplicación. Por ejemplo, al usar la biblioteca laravel-precognition-vue, puede agregar encabezados de solicitud adicionales a cada solicitud saliente en el archivo resources/js/app.js de su aplicación:

import { client } from 'laravel-precognition-vue';
 
client.axios().defaults.headers.common['Authorization'] = authToken;

O, si ya tiene una instancia de Axios configurada para su aplicación, puede indicarle a Precognition que use esa instancia en su lugar:

import Axios from 'axios';
import { client } from 'laravel-precognition-vue';
 
window.axios = Axios.create()
window.axios.defaults.headers.common['Authorization'] = authToken;
 
client.use(window.axios)

Advertencia Las bibliotecas de Precognition con sabor a Inertia solo usarán la instancia de Axios configurada para las solicitudes de validación. Las presentaciones de formularios siempre se enviarán mediante Inertia.

Personalización de las reglas de validación

Es posible personalizar las reglas de validación ejecutadas durante una solicitud precognitiva utilizando el método isPrecognitive de la solicitud.

Por ejemplo, en un formulario de creación de usuarios, es posible que deseemos validar que una contraseña no esté comprometida solo en el envío final del formulario. Para las solicitudes de validación precognitiva, simplemente validaremos que la contraseña sea obligatoria y tenga un mínimo de 8 caracteres. Usando el método isPrecognitive, podemos personalizar las reglas definidas por nuestra solicitud de formulario:

<?php
 
namespace App\Http\Requests;
 
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
 
class StoreUserRequest extends FormRequest
{
/**
* Obtener las reglas de validación que se aplican a la solicitud.
*
* @return array
*/
protected function rules()
{
return [
'password' => [
'required',
$this->isPrecognitive()
? Password::min(8)
: Password::min(8)->uncompromised(),
],
// ...
];
}
}

Manejo de la carga de archivos

Por defecto, Laravel Precognition no carga ni valida archivos durante una solicitud de validación precognitiva. Esto garantiza que los archivos grandes no se carguen innecesariamente varias veces.

Debido a este comportamiento, debe asegurarse de que su aplicación personalice las reglas de validación correspondientes de la solicitud de formulario para especificar que el campo solo es obligatorio para envíos completos del formulario:

/**
* Obtener las reglas de validación que se aplican a la solicitud.
*
* @return array
*/
protected function rules()
{
return [
'avatar' => [
...$this->isPrecognitive() ? [] : ['required'],
'image',
'mimes:jpg,png'
'dimensions:ratio=3/2',
],
// ...
];
}

Si desea incluir archivos en cada solicitud de validación, puede invocar la función validateFiles en su instancia de formulario del lado del cliente:

form.validateFiles();

Gestión de efectos secundarios

Al agregar el middleware HandlePrecognitiveRequests a una ruta, debe considerar si hay algún efecto secundario en otros middleware que se deba omitir durante una solicitud precognitiva.

Por ejemplo, puede tener un middleware que incremente el número total de "interacciones" que tiene cada usuario con su aplicación, pero es posible que no desee que las solicitudes precognitivas se cuenten como una interacción. Para lograr esto, podemos verificar el método isPrecognitive de la solicitud antes de incrementar el conteo de interacciones:

<?php
 
namespace App\Http\Middleware;
 
use App\Facades\Interaction;
use Closure;
use Illuminate\Http\Request;
 
class InteractionMiddleware
{
/**
* Manejar una solicitud entrante.
*/
public function handle(Request $request, Closure $next): mixed
{
if (! $request->isPrecognitive()) {
Interaction::incrementFor($request->user());
}
 
return $next($request);
}
}

Pruebas

Si desea realizar solicitudes precognitivas en sus pruebas, el TestCase de Laravel incluye un ayudante withPrecognition que agregará el encabezado de solicitud Precognition.

Además, si desea afirmar que una solicitud precognitiva fue exitosa, por ejemplo, no devolvió errores de validación, puede usar el método assertSuccessfulPrecognition en la respuesta:

public function test_it_validates_registration_form_with_precognition()
{
$response = $this->withPrecognition()
->post('/register', [
'name' => 'Taylor Otwell',
]);
 
$response->assertSuccessfulPrecognition();
$this->assertSame(0, User::count());
}