> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Precognition

> 在表單送出前即時執行伺服器端驗證的 Laravel 功能

## 什麼是 Precognition

Precognition 是在表單送出前執行伺服器端驗證的機制。
不需要在前端重複定義驗證規則，可直接使用 Laravel 的規則。

與一般請求不同，Precognition 請求會執行路由的 middleware 與 form request 的驗證，但不會執行 controller 方法本體。
因此適合輸入過程中的即時驗證。

## 安裝

在 Laravel 13 中，後端不需要另行安裝 `laravel/precognition`。
所需的是前端的 helper 套件。

* Vue: `laravel-precognition-vue`
* React: `laravel-precognition-react`
* Alpine.js: `laravel-precognition-alpine`

```shell theme={null}
npm install laravel-precognition-vue
```

```shell theme={null}
npm install laravel-precognition-react
```

```shell theme={null}
npm install laravel-precognition-alpine
```

<Info>
  Inertia 自 2.3 起內建 Precognition 支援。Inertia 3 也可直接使用。
  使用 Inertia form 時，通常不需要額外安裝 `laravel-precognition-vue` / `laravel-precognition-react`。
</Info>

## 後端設定

在路由加入 `HandlePrecognitiveRequests` middleware。
實務上建議將驗證規則集中在 form request。
集中在 form request 有助於規則的重用與職責分離。

```php theme={null}
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
use Illuminate\Support\Facades\Route;

Route::post('/users', function (StoreUserRequest $request) {
    // 只有正式送出時才會執行這裡
})->middleware([HandlePrecognitiveRequests::class]);
```

若有具副作用的自訂 middleware，在 Precognition 時請跳過。

```php theme={null}
public function handle(Request $request, Closure $next): mixed
{
    if (! $request->isPrecognitive()) {
        Interaction::incrementFor($request->user());
    }

    return $next($request);
}
```

## 前端整合

### Alpine.js（Blade）

```html theme={null}
<form x-data="{
    form: $form('post', '/users', { name: '', email: '' }),
}">
    @csrf
    <input x-model="form.name" @change="form.validate('name')" />
    <template x-if="form.invalid('name')">
        <div x-text="form.errors.name"></div>
    </template>
</form>
```

### Vue（Inertia.js）

```vue theme={null}
<script setup>
import { useForm } from 'laravel-precognition-vue';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});
</script>

<template>
    <input v-model="form.name" @change="form.validate('name')" />
    <div v-if="form.invalid('name')">{{ form.errors.name }}</div>
</template>
```

### React（Inertia.js）

```jsx theme={null}
import { useForm } from 'laravel-precognition-react';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});

<input
    value={form.data.name}
    onChange={(e) => form.setData('name', e.target.value)}
    onBlur={() => form.validate('name')}
/>
```

### 使用 Axios 的原生 JS

Precognition 函式庫使用 Axios。
若要沿用既有的 Axios 實例，可用 `client.use()` 替換。

```js theme={null}
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);
```

## 控制驗證的時機

以 `validate()` 進行逐項驗證。

```js theme={null}
form.validate('email');
```

可用 `setValidationTimeout()` 調整 debounce 時間。

```js theme={null}
form.setValidationTimeout(3000);
```

若要每次都驗證檔案，使用 `validateFiles()`。

```js theme={null}
form.validateFiles();
```

陣列輸入可以萬用字元驗證。

```js theme={null}
form.validate('users.*.email');
```

## Form Helper

`useForm()` 可一併管理送出狀態與錯誤狀態。

* `validating`：正在進行驗證請求
* `processing`：正在送出
* `errors`：錯誤清單
* `valid('field')` / `invalid('field')`：欄位的驗證狀態
* `submit()`：正常送出

```js theme={null}
const submit = () => form.submit()
    .then(() => form.reset());
```

## 一般請求與 Precognition 請求的比較

下圖顯示一般請求與 Precognition 請求的處理差異。

```mermaid theme={null}
sequenceDiagram
    participant User as 使用者
    participant Frontend as 前端
    participant Server as Laravel 伺服器

    User->>Frontend: 表單輸入
    Frontend->>Server: Precognition 請求（Precognition: true header）
    Server->>Server: 執行驗證（不執行 controller 邏輯）
    Server-->>Frontend: 驗證結果
    Frontend-->>User: 即時錯誤顯示
    User->>Frontend: 表單送出
    Frontend->>Server: 一般請求
    Server-->>Frontend: 回應
```

## 相關連結

* [Laravel 官方：Precognition](https://laravel.com/docs/precognition)
* [Laravel 官方：Validation](https://laravel.com/docs/validation)
