Files
laravelDocScrappy/output/12.x/precognition.md
2025-09-02 15:19:23 +02:00

1767 lines
42 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Precognition
* Introduction
* Live Validation
* Using Vue
* Using Vue and Inertia
* Using React
* Using React and Inertia
* Using Alpine and Blade
* Configuring Axios
* Customizing Validation Rules
* Handling File Uploads
* Managing Side-Effects
* Testing
## Introduction
Laravel Precognition allows you to anticipate the outcome of a future HTTP
request. One of the primary use cases of Precognition is the ability to
provide "live" validation for your frontend JavaScript application without
having to duplicate your application's backend validation rules. Precognition
pairs especially well with Laravel's Inertia-based [starter
kits](/docs/12.x/starter-kits).
When Laravel receives a "precognitive request", it will execute all of the
route's middleware and resolve the route's controller dependencies, including
validating [form requests](/docs/12.x/validation#form-request-validation) \-
but it will not actually execute the route's controller method.
## Live Validation
### Using Vue
Using Laravel Precognition, you can offer live validation experiences to your
users without having to duplicate your validation rules in your frontend Vue
application. To illustrate how it works, let's build a form for creating new
users within our application.
First, to enable Precognition for a route, the `HandlePrecognitiveRequests`
middleware should be added to the route definition. You should also create a
[form request](/docs/12.x/validation#form-request-validation) to house the
route's validation rules:
1use App\Http\Requests\StoreUserRequest;
2use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
3 
4Route::post('/users', function (StoreUserRequest $request) {
5 // ...
6})->middleware([HandlePrecognitiveRequests::class]);
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);
Next, you should install the Laravel Precognition frontend helpers for Vue via
NPM:
1npm install laravel-precognition-vue
npm install laravel-precognition-vue
With the Laravel Precognition package installed, you can now create a form
object using Precognition's `useForm` function, providing the HTTP method
(`post`), the target URL (`/users`), and the initial form data.
Then, to enable live validation, invoke the form's `validate` method on each
input's `change` event, providing the input's name:
1<script setup>
2import { useForm } from 'laravel-precognition-vue';
3 
4const form = useForm('post', '/users', {
5 name: '',
6 email: '',
7});
8 
9const submit = () => form.submit();
10</script>
11 
12<template>
13 <form @submit.prevent="submit">
14 <label for="name">Name</label>
15 <input
16 id="name"
17 v-model="form.name"
18 @change="form.validate('name')"
19 />
20 <div v-if="form.invalid('name')">
21 {{ form.errors.name }}
22 </div>
23 
24 <label for="email">Email</label>
25 <input
26 id="email"
27 type="email"
28 v-model="form.email"
29 @change="form.validate('email')"
30 />
31 <div v-if="form.invalid('email')">
32 {{ form.errors.email }}
33 </div>
34 
35 <button :disabled="form.processing">
36 Create User
37 </button>
38 </form>
39</template>
<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>
Now, as the form is filled by the user, Precognition will provide live
validation output powered by the validation rules in the route's form request.
When the form's inputs are changed, a debounced "precognitive" validation
request will be sent to your Laravel application. You may configure the
debounce timeout by calling the form's `setValidationTimeout` function:
1form.setValidationTimeout(3000);
form.setValidationTimeout(3000);
When a validation request is in-flight, the form's `validating` property will
be `true`:
1<div v-if="form.validating">
2 Validating...
3</div>
<div v-if="form.validating">
Validating...
</div>
Any validation errors returned during a validation request or a form
submission will automatically populate the form's `errors` object:
1<div v-if="form.invalid('email')">
2 {{ form.errors.email }}
3</div>
<div v-if="form.invalid('email')">
{{ form.errors.email }}
</div>
You can determine if the form has any errors using the form's `hasErrors`
property:
1<div v-if="form.hasErrors">
2 <!-- ... -->
3</div>
<div v-if="form.hasErrors">
<!-- ... -->
</div>
You may also determine if an input has passed or failed validation by passing
the input's name to the form's `valid` and `invalid` functions, respectively:
1<span v-if="form.valid('email')">
2 ✅
3</span>
4 
5<span v-else-if="form.invalid('email')">
6 ❌
7</span>
<span v-if="form.valid('email')">
</span>
<span v-else-if="form.invalid('email')">
</span>
A form input will only appear as valid or invalid once it has changed and a
validation response has been received.
If you are validating a subset of a form's inputs with Precognition, it can be
useful to manually clear errors. You may use the form's `forgetError` function
to achieve this:
1<input
2 id="avatar"
3 type="file"
4 @change="(e) => {
5 form.avatar = e.target.files[0]
6 
7 form.forgetError('avatar')
8 }"
9>
<input
id="avatar"
type="file"
@change="(e) => {
form.avatar = e.target.files[0]
form.forgetError('avatar')
}"
>
As we have seen, you can hook into an input's `change` event and validate
individual inputs as the user interacts with them; however, you may need to
validate inputs that the user has not yet interacted with. This is common when
building a "wizard", where you want to validate all visible inputs, whether
the user has interacted with them or not, before moving to the next step.
To do this with Precognition, you should call the `validate` method passing
the field names you wish to validate to the `only` configuration key. You may
handle the validation result with `onSuccess` or `onValidationError`
callbacks:
1<button
2 type="button"
3 @click="form.validate({
4 only: ['name', 'email', 'phone'],
5 onSuccess: (response) => nextStep(),
6 onValidationError: (response) => /* ... */,
7 })"
8>Next Step</button>
<button
type="button"
@click="form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})"
>Next Step</button>
Of course, you may also execute code in reaction to the response to the form
submission. The form's `submit` function returns an Axios request promise.
This provides a convenient way to access the response payload, reset the form
inputs on successful submission, or handle a failed request:
1const submit = () => form.submit()
2 .then(response => {
3 form.reset();
4 
5 alert('User created.');
6 })
7 .catch(error => {
8 alert('An error occurred.');
9 });
const submit = () => form.submit()
.then(response => {
form.reset();
alert('User created.');
})
.catch(error => {
alert('An error occurred.');
});
You may determine if a form submission request is in-flight by inspecting the
form's `processing` property:
1<button :disabled="form.processing">
2 Submit
3</button>
<button :disabled="form.processing">
Submit
</button>
### Using Vue and Inertia
If you would like a head start when developing your Laravel application with
Vue and Inertia, consider using one of our [starter kits](/docs/12.x/starter-
kits). Laravel's starter kits provide backend and frontend authentication
scaffolding for your new Laravel application.
Before using Precognition with Vue and Inertia, be sure to review our general
documentation on using Precognition with Vue. When using Vue with Inertia, you
will need to install the Inertia compatible Precognition library via NPM:
1npm install laravel-precognition-vue-inertia
npm install laravel-precognition-vue-inertia
Once installed, Precognition's `useForm` function will return an Inertia [form
helper](https://inertiajs.com/forms#form-helper) augmented with the validation
features discussed above.
The form helper's `submit` method has been streamlined, removing the need to
specify the HTTP method or URL. Instead, you may pass Inertia's [visit
options](https://inertiajs.com/manual-visits) as the first and only argument.
In addition, the `submit` method does not return a Promise as seen in the Vue
example above. Instead, you may provide any of Inertia's supported [event
callbacks](https://inertiajs.com/manual-visits#event-callbacks) in the visit
options given to the `submit` method:
1<script setup>
2import { useForm } from 'laravel-precognition-vue-inertia';
3 
4const form = useForm('post', '/users', {
5 name: '',
6 email: '',
7});
8 
9const submit = () => form.submit({
10 preserveScroll: true,
11 onSuccess: () => form.reset(),
12});
13</script>
<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>
### Using React
Using Laravel Precognition, you can offer live validation experiences to your
users without having to duplicate your validation rules in your frontend React
application. To illustrate how it works, let's build a form for creating new
users within our application.
First, to enable Precognition for a route, the `HandlePrecognitiveRequests`
middleware should be added to the route definition. You should also create a
[form request](/docs/12.x/validation#form-request-validation) to house the
route's validation rules:
1use App\Http\Requests\StoreUserRequest;
2use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
3 
4Route::post('/users', function (StoreUserRequest $request) {
5 // ...
6})->middleware([HandlePrecognitiveRequests::class]);
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (StoreUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);
Next, you should install the Laravel Precognition frontend helpers for React
via NPM:
1npm install laravel-precognition-react
npm install laravel-precognition-react
With the Laravel Precognition package installed, you can now create a form
object using Precognition's `useForm` function, providing the HTTP method
(`post`), the target URL (`/users`), and the initial form data.
To enable live validation, you should listen to each input's `change` and
`blur` event. In the `change` event handler, you should set the form's data
with the `setData` function, passing the input's name and new value. Then, in
the `blur` event handler invoke the form's `validate` method, providing the
input's name:
1import { useForm } from 'laravel-precognition-react';
2 
3export default function Form() {
4 const form = useForm('post', '/users', {
5 name: '',
6 email: '',
7 });
8 
9 const submit = (e) => {
10 e.preventDefault();
11 
12 form.submit();
13 };
14 
15 return (
16 <form onSubmit={submit}>
17 <label htmlFor="name">Name</label>
18 <input
19 id="name"
20 value={form.data.name}
21 onChange={(e) => form.setData('name', e.target.value)}
22 onBlur={() => form.validate('name')}
23 />
24 {form.invalid('name') && <div>{form.errors.name}</div>}
25 
26 <label htmlFor="email">Email</label>
27 <input
28 id="email"
29 value={form.data.email}
30 onChange={(e) => form.setData('email', e.target.value)}
31 onBlur={() => form.validate('email')}
32 />
33 {form.invalid('email') && <div>{form.errors.email}</div>}
34 
35 <button disabled={form.processing}>
36 Create User
37 </button>
38 </form>
39 );
40};
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 htmlFor="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 htmlFor="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>
);
};
Now, as the form is filled by the user, Precognition will provide live
validation output powered by the validation rules in the route's form request.
When the form's inputs are changed, a debounced "precognitive" validation
request will be sent to your Laravel application. You may configure the
debounce timeout by calling the form's `setValidationTimeout` function:
1form.setValidationTimeout(3000);
form.setValidationTimeout(3000);
When a validation request is in-flight, the form's `validating` property will
be `true`:
1{form.validating && <div>Validating...</div>}
{form.validating && <div>Validating...</div>}
Any validation errors returned during a validation request or a form
submission will automatically populate the form's `errors` object:
1{form.invalid('email') && <div>{form.errors.email}</div>}
{form.invalid('email') && <div>{form.errors.email}</div>}
You can determine if the form has any errors using the form's `hasErrors`
property:
1{form.hasErrors && <div><!-- ... --></div>}
{form.hasErrors && <div><!-- ... --></div>}
You may also determine if an input has passed or failed validation by passing
the input's name to the form's `valid` and `invalid` functions, respectively:
1{form.valid('email') && <span></span>}
2 
3{form.invalid('email') && <span></span>}
{form.valid('email') && <span></span>}
{form.invalid('email') && <span></span>}
A form input will only appear as valid or invalid once it has changed and a
validation response has been received.
If you are validating a subset of a form's inputs with Precognition, it can be
useful to manually clear errors. You may use the form's `forgetError` function
to achieve this:
1<input
2 id="avatar"
3 type="file"
4 onChange={(e) => {
5 form.setData('avatar', e.target.value);
6 
7 form.forgetError('avatar');
8 }}
9>
<input
id="avatar"
type="file"
onChange={(e) => {
form.setData('avatar', e.target.value);
form.forgetError('avatar');
}}
>
As we have seen, you can hook into an input's `blur` event and validate
individual inputs as the user interacts with them; however, you may need to
validate inputs that the user has not yet interacted with. This is common when
building a "wizard", where you want to validate all visible inputs, whether
the user has interacted with them or not, before moving to the next step.
To do this with Precognition, you should call the `validate` method passing
the field names you wish to validate to the `only` configuration key. You may
handle the validation result with `onSuccess` or `onValidationError`
callbacks:
1<button
2 type="button"
3 onClick={() => form.validate({
4 only: ['name', 'email', 'phone'],
5 onSuccess: (response) => nextStep(),
6 onValidationError: (response) => /* ... */,
7 })}
8>Next Step</button>
<button
type="button"
onClick={() => form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})}
>Next Step</button>
Of course, you may also execute code in reaction to the response to the form
submission. The form's `submit` function returns an Axios request promise.
This provides a convenient way to access the response payload, reset the
form's inputs on a successful form submission, or handle a failed request:
1const submit = (e) => {
2 e.preventDefault();
3 
4 form.submit()
5 .then(response => {
6 form.reset();
7 
8 alert('User created.');
9 })
10 .catch(error => {
11 alert('An error occurred.');
12 });
13};
const submit = (e) => {
e.preventDefault();
form.submit()
.then(response => {
form.reset();
alert('User created.');
})
.catch(error => {
alert('An error occurred.');
});
};
You may determine if a form submission request is in-flight by inspecting the
form's `processing` property:
1<button disabled={form.processing}>
2 Submit
3</button>
<button disabled={form.processing}>
Submit
</button>
### Using React and Inertia
If you would like a head start when developing your Laravel application with
React and Inertia, consider using one of our [starter
kits](/docs/12.x/starter-kits). Laravel's starter kits provide backend and
frontend authentication scaffolding for your new Laravel application.
Before using Precognition with React and Inertia, be sure to review our
general documentation on using Precognition with React. When using React with
Inertia, you will need to install the Inertia compatible Precognition library
via NPM:
1npm install laravel-precognition-react-inertia
npm install laravel-precognition-react-inertia
Once installed, Precognition's `useForm` function will return an Inertia [form
helper](https://inertiajs.com/forms#form-helper) augmented with the validation
features discussed above.
The form helper's `submit` method has been streamlined, removing the need to
specify the HTTP method or URL. Instead, you may pass Inertia's [visit
options](https://inertiajs.com/manual-visits) as the first and only argument.
In addition, the `submit` method does not return a Promise as seen in the
React example above. Instead, you may provide any of Inertia's supported
[event callbacks](https://inertiajs.com/manual-visits#event-callbacks) in the
visit options given to the `submit` method:
1import { useForm } from 'laravel-precognition-react-inertia';
2 
3const form = useForm('post', '/users', {
4 name: '',
5 email: '',
6});
7 
8const submit = (e) => {
9 e.preventDefault();
10 
11 form.submit({
12 preserveScroll: true,
13 onSuccess: () => form.reset(),
14 });
15};
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(),
});
};
### Using Alpine and Blade
Using Laravel Precognition, you can offer live validation experiences to your
users without having to duplicate your validation rules in your frontend
Alpine application. To illustrate how it works, let's build a form for
creating new users within our application.
First, to enable Precognition for a route, the `HandlePrecognitiveRequests`
middleware should be added to the route definition. You should also create a
[form request](/docs/12.x/validation#form-request-validation) to house the
route's validation rules:
1use App\Http\Requests\CreateUserRequest;
2use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
3 
4Route::post('/users', function (CreateUserRequest $request) {
5 // ...
6})->middleware([HandlePrecognitiveRequests::class]);
use App\Http\Requests\CreateUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
Route::post('/users', function (CreateUserRequest $request) {
// ...
})->middleware([HandlePrecognitiveRequests::class]);
Next, you should install the Laravel Precognition frontend helpers for Alpine
via NPM:
1npm install laravel-precognition-alpine
npm install laravel-precognition-alpine
Then, register the Precognition plugin with Alpine in your
`resources/js/app.js` file:
1import Alpine from 'alpinejs';
2import Precognition from 'laravel-precognition-alpine';
3 
4window.Alpine = Alpine;
5 
6Alpine.plugin(Precognition);
7Alpine.start();
import Alpine from 'alpinejs';
import Precognition from 'laravel-precognition-alpine';
window.Alpine = Alpine;
Alpine.plugin(Precognition);
Alpine.start();
With the Laravel Precognition package installed and registered, you can now
create a form object using Precognition's `$form` "magic", providing the HTTP
method (`post`), the target URL (`/users`), and the initial form data.
To enable live validation, you should bind the form's data to its relevant
input and then listen to each input's `change` event. In the `change` event
handler, you should invoke the form's `validate` method, providing the input's
name:
1<form x-data="{
2 form: $form('post', '/register', {
3 name: '',
4 email: '',
5 }),
6}">
7 @csrf
8 <label for="name">Name</label>
9 <input
10 id="name"
11 name="name"
12 x-model="form.name"
13 @change="form.validate('name')"
14 />
15 <template x-if="form.invalid('name')">
16 <div x-text="form.errors.name"></div>
17 </template>
18 
19 <label for="email">Email</label>
20 <input
21 id="email"
22 name="email"
23 x-model="form.email"
24 @change="form.validate('email')"
25 />
26 <template x-if="form.invalid('email')">
27 <div x-text="form.errors.email"></div>
28 </template>
29 
30 <button :disabled="form.processing">
31 Create User
32 </button>
33</form>
<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>
Now, as the form is filled by the user, Precognition will provide live
validation output powered by the validation rules in the route's form request.
When the form's inputs are changed, a debounced "precognitive" validation
request will be sent to your Laravel application. You may configure the
debounce timeout by calling the form's `setValidationTimeout` function:
1form.setValidationTimeout(3000);
form.setValidationTimeout(3000);
When a validation request is in-flight, the form's `validating` property will
be `true`:
1<template x-if="form.validating">
2 <div>Validating...</div>
3</template>
<template x-if="form.validating">
<div>Validating...</div>
</template>
Any validation errors returned during a validation request or a form
submission will automatically populate the form's `errors` object:
1<template x-if="form.invalid('email')">
2 <div x-text="form.errors.email"></div>
3</template>
<template x-if="form.invalid('email')">
<div x-text="form.errors.email"></div>
</template>
You can determine if the form has any errors using the form's `hasErrors`
property:
1<template x-if="form.hasErrors">
2 <div><!-- ... --></div>
3</template>
<template x-if="form.hasErrors">
<div><!-- ... --></div>
</template>
You may also determine if an input has passed or failed validation by passing
the input's name to the form's `valid` and `invalid` functions, respectively:
1<template x-if="form.valid('email')">
2 <span></span>
3</template>
4 
5<template x-if="form.invalid('email')">
6 <span></span>
7</template>
<template x-if="form.valid('email')">
<span></span>
</template>
<template x-if="form.invalid('email')">
<span></span>
</template>
A form input will only appear as valid or invalid once it has changed and a
validation response has been received.
As we have seen, you can hook into an input's `change` event and validate
individual inputs as the user interacts with them; however, you may need to
validate inputs that the user has not yet interacted with. This is common when
building a "wizard", where you want to validate all visible inputs, whether
the user has interacted with them or not, before moving to the next step.
To do this with Precognition, you should call the `validate` method passing
the field names you wish to validate to the `only` configuration key. You may
handle the validation result with `onSuccess` or `onValidationError`
callbacks:
1<button
2 type="button"
3 @click="form.validate({
4 only: ['name', 'email', 'phone'],
5 onSuccess: (response) => nextStep(),
6 onValidationError: (response) => /* ... */,
7 })"
8>Next Step</button>
<button
type="button"
@click="form.validate({
only: ['name', 'email', 'phone'],
onSuccess: (response) => nextStep(),
onValidationError: (response) => /* ... */,
})"
>Next Step</button>
You may determine if a form submission request is in-flight by inspecting the
form's `processing` property:
1<button :disabled="form.processing">
2 Submit
3</button>
<button :disabled="form.processing">
Submit
</button>
#### Repopulating Old Form Data
In the user creation example discussed above, we are using Precognition to
perform live validation; however, we are performing a traditional server-side
form submission to submit the form. So, the form should be populated with any
"old" input and validation errors returned from the server-side form
submission:
1<form x-data="{
2 form: $form('post', '/register', {
3 name: '{{ old('name') }}',
4 email: '{{ old('email') }}',
5 }).setErrors({{ Js::from($errors->messages()) }}),
6}">
<form x-data="{
form: $form('post', '/register', {
name: '{{ old('name') }}',
email: '{{ old('email') }}',
}).setErrors({{ Js::from($errors->messages()) }}),
}">
Alternatively, if you would like to submit the form via XHR you may use the
form's `submit` function, which returns an Axios request promise:
1<form
2 x-data="{
3 form: $form('post', '/register', {
4 name: '',
5 email: '',
6 }),
7 submit() {
8 this.form.submit()
9 .then(response => {
10 this.form.reset();
11 
12 alert('User created.')
13 })
14 .catch(error => {
15 alert('An error occurred.');
16 });
17 },
18 }"
19 @submit.prevent="submit"
20>
<form
x-data="{
form: $form('post', '/register', {
name: '',
email: '',
}),
submit() {
this.form.submit()
.then(response => {
this.form.reset();
alert('User created.')
})
.catch(error => {
alert('An error occurred.');
});
},
}"
@submit.prevent="submit"
>
### Configuring Axios
The Precognition validation libraries use the
[Axios](https://github.com/axios/axios) HTTP client to send requests to your
application's backend. For convenience, the Axios instance may be customized
if required by your application. For example, when using the `laravel-
precognition-vue` library, you may add additional request headers to each
outgoing request in your application's `resources/js/app.js` file:
1import { client } from 'laravel-precognition-vue';
2 
3client.axios().defaults.headers.common['Authorization'] = authToken;
import { client } from 'laravel-precognition-vue';
client.axios().defaults.headers.common['Authorization'] = authToken;
Or, if you already have a configured Axios instance for your application, you
may tell Precognition to use that instance instead:
1import Axios from 'axios';
2import { client } from 'laravel-precognition-vue';
3 
4window.axios = Axios.create()
5window.axios.defaults.headers.common['Authorization'] = authToken;
6 
7client.use(window.axios)
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)
The Inertia flavored Precognition libraries will only use the configured Axios
instance for validation requests. Form submissions will always be sent by
Inertia.
## Customizing Validation Rules
It is possible to customize the validation rules executed during a
precognitive request by using the request's `isPrecognitive` method.
For example, on a user creation form, we may want to validate that a password
is "uncompromised" only on the final form submission. For precognitive
validation requests, we will simply validate that the password is required and
has a minimum of 8 characters. Using the `isPrecognitive` method, we can
customize the rules defined by our form request:
1<?php
2 
3namespace App\Http\Requests;
4 
5use Illuminate\Foundation\Http\FormRequest;
6use Illuminate\Validation\Rules\Password;
7 
8class StoreUserRequest extends FormRequest
9{
10 /**
11 * Get the validation rules that apply to the request.
12 *
13 * @return array
14 */
15 protected function rules()
16 {
17 return [
18 'password' => [
19 'required',
20 $this->isPrecognitive()
21 ? Password::min(8)
22 : Password::min(8)->uncompromised(),
23 ],
24 // ...
25 ];
26 }
27}
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class StoreUserRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
protected function rules()
{
return [
'password' => [
'required',
$this->isPrecognitive()
? Password::min(8)
: Password::min(8)->uncompromised(),
],
// ...
];
}
}
## Handling File Uploads
By default, Laravel Precognition does not upload or validate files during a
precognitive validation request. This ensure that large files are not
unnecessarily uploaded multiple times.
Because of this behavior, you should ensure that your application customizes
the corresponding form request's validation rules to specify the field is only
required for full form submissions:
1/**
2 * Get the validation rules that apply to the request.
3 *
4 * @return array
5 */
6protected function rules()
7{
8 return [
9 'avatar' => [
10 ...$this->isPrecognitive() ? [] : ['required'],
11 'image',
12 'mimes:jpg,png',
13 'dimensions:ratio=3/2',
14 ],
15 // ...
16 ];
17}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
protected function rules()
{
return [
'avatar' => [
...$this->isPrecognitive() ? [] : ['required'],
'image',
'mimes:jpg,png',
'dimensions:ratio=3/2',
],
// ...
];
}
If you would like to include files in every validation request, you may invoke
the `validateFiles` function on your client-side form instance:
1form.validateFiles();
form.validateFiles();
## Managing Side-Effects
When adding the `HandlePrecognitiveRequests` middleware to a route, you should
consider if there are any side-effects in _other_ middleware that should be
skipped during a precognitive request.
For example, you may have a middleware that increments the total number of
"interactions" each user has with your application, but you may not want
precognitive requests to be counted as an interaction. To accomplish this, we
may check the request's `isPrecognitive` method before incrementing the
interaction count:
1<?php
2 
3namespace App\Http\Middleware;
4 
5use App\Facades\Interaction;
6use Closure;
7use Illuminate\Http\Request;
8 
9class InteractionMiddleware
10{
11 /**
12 * Handle an incoming request.
13 */
14 public function handle(Request $request, Closure $next): mixed
15 {
16 if (! $request->isPrecognitive()) {
17 Interaction::incrementFor($request->user());
18 }
19 
20 return $next($request);
21 }
22}
<?php
namespace App\Http\Middleware;
use App\Facades\Interaction;
use Closure;
use Illuminate\Http\Request;
class InteractionMiddleware
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): mixed
{
if (! $request->isPrecognitive()) {
Interaction::incrementFor($request->user());
}
return $next($request);
}
}
## Testing
If you would like to make precognitive requests in your tests, Laravel's
`TestCase` includes a `withPrecognition` helper which will add the
`Precognition` request header.
Additionally, if you would like to assert that a precognitive request was
successful, e.g., did not return any validation errors, you may use the
`assertSuccessfulPrecognition` method on the response:
Pest PHPUnit
1it('validates registration form with precognition', function () {
2 $response = $this->withPrecognition()
3 ->post('/register', [
4 'name' => 'Taylor Otwell',
5 ]);
6 
7 $response->assertSuccessfulPrecognition();
8 
9 expect(User::count())->toBe(0);
10});
it('validates registration form with precognition', function () {
$response = $this->withPrecognition()
->post('/register', [
'name' => 'Taylor Otwell',
]);
$response->assertSuccessfulPrecognition();
expect(User::count())->toBe(0);
});
1public function test_it_validates_registration_form_with_precognition()
2{
3 $response = $this->withPrecognition()
4 ->post('/register', [
5 'name' => 'Taylor Otwell',
6 ]);
7 
8 $response->assertSuccessfulPrecognition();
9 $this->assertSame(0, User::count());
10}
public function test_it_validates_registration_form_with_precognition()
{
$response = $this->withPrecognition()
->post('/register', [
'name' => 'Taylor Otwell',
]);
$response->assertSuccessfulPrecognition();
$this->assertSame(0, User::count());
}