Skip to content

Precognition

はじめに

Laravel Precognitionを使用すると、将来のHTTPリクエストの結果を予測することができます。Precognitionの主な用途の一つは、アプリケーションのバックエンドのバリデーションルールを複製することなく、フロントエンドのJavaScriptアプリケーションに「ライブ」バリデーションを提供することです。Precognitionは、特にLaravelのInertiaベースのスターターキットと組み合わせると効果的です。

Laravelが「予知リクエスト」を受け取ると、ルートのミドルウェアをすべて実行し、ルートのコントローラの依存関係を解決します。これには、フォームリクエストのバリデーションも含まれますが、実際にはルートのコントローラメソッドは実行されません。

ライブバリデーション

Vueを使用する

Laravel Precognitionを使用すると、バリデーションルールをフロントエンドのVueアプリケーションに複製することなく、ユーザーにライブバリデーションの体験を提供できます。どのように機能するかを説明するために、アプリケーション内で新しいユーザーを作成するためのフォームを構築しましょう。

まず、ルートにPrecognitionを有効にするために、HandlePrecognitiveRequestsミドルウェアをルート定義に追加する必要があります。また、ルートのバリデーションルールを格納するためのフォームリクエストを作成する必要があります。

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;

Route::post('/users', function (StoreUserRequest $request) {
    // ...
})->middleware([HandlePrecognitiveRequests::class]);

次に、Laravel PrecognitionのフロントエンドヘルパーをVue用にNPM経由でインストールします。

npm install laravel-precognition-vue

Laravel Precognitionパッケージをインストールしたら、PrecognitionのuseForm関数を使用してフォームオブジェクトを作成できます。HTTPメソッド(post)、ターゲットURL(/users)、および初期フォームデータを提供します。

次に、ライブバリデーションを有効にするために、各入力のchangeイベントでフォームのvalidateメソッドを呼び出し、入力の名前を渡します。

<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>

これで、ユーザーがフォームを入力すると、Precognitionはルートのフォームリクエストのバリデーションルールに基づいてライブバリデーションを提供します。フォームの入力が変更されると、デバウンスされた「予知」バリデーションリクエストがLaravelアプリケーションに送信されます。デバウンスタイムアウトは、フォームのsetValidationTimeout関数を呼び出して設定できます。

form.setValidationTimeout(3000);

バリデーションリクエストが進行中の場合、フォームのvalidatingプロパティはtrueになります。

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

バリデーションリクエスト中またはフォーム送信中に返されたバリデーションエラーは、自動的にフォームのerrorsオブジェクトに入力されます。

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

フォームにエラーがあるかどうかは、フォームのhasErrorsプロパティを使用して確認できます。

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

入力がバリデーションに合格したか失敗したかは、それぞれフォームのvalid関数とinvalid関数に入力の名前を渡すことで確認できます。

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

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

Warning

フォーム入力は、変更されてバリデーションレスポンスを受け取った後にのみ、有効または無効として表示されます。

Precognitionでフォームの入力のサブセットをバリデーションする場合、エラーを手動でクリアすると便利です。これは、フォームのforgetError関数を使用して行うことができます。

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

        form.forgetError('avatar')
    }"
>

これまで見てきたように、入力のchangeイベントにフックして、ユーザーが入力と対話するときに個々の入力をバリデーションすることができます。しかし、ユーザーがまだ対話していない入力をバリデーションする必要がある場合があります。これは、ユーザーが対話したかどうかに関係なく、すべての表示されている入力をバリデーションしたい「ウィザード」を構築する場合によくあります。

Precognitionでこれを行うには、バリデーションしたいフィールドを「touched」としてマークするために、それらの名前をtouchメソッドに渡します。次に、validateメソッドをonSuccessまたはonValidationErrorコールバックで呼び出します。

<button
    type="button" 
    @click="form.touch(['name', 'email', 'phone']).validate({
        onSuccess: (response) => nextStep(),
        onValidationError: (response) => /* ... */,
    })"
>Next Step</button>

もちろん、フォーム送信のレスポンスに反応してコードを実行することもできます。フォームのsubmit関数はAxiosリクエストのPromiseを返します。これにより、レスポンスペイロードにアクセスしたり、送信が成功した場合にフォーム入力をリセットしたり、リクエストが失敗した場合に対処したりする便利な方法が提供されます。

const submit = () => form.submit()
    .then(response => {
        form.reset();

        alert('User created.');
    })
    .catch(error => {
        alert('An error occurred.');
    });

フォーム送信リクエストが進行中かどうかは、フォームのprocessingプロパティを検査することで確認できます。

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

VueとInertiaを使用する

Note

VueとInertiaを使用してLaravelアプリケーションを開発する際にスタートアップをスムーズにしたい場合は、スターターキットのいずれかを使用することを検討してください。Laravelのスターターキットは、新しいLaravelアプリケーションのためのバックエンドとフロントエンドの認証スキャフォールディングを提供します。

PrecognitionをVueとInertiaで使用する前に、VueでPrecognitionを使用するに関する一般的なドキュメントを確認してください。VueとInertiaを使用する場合、Inertia互換のPrecognitionライブラリをNPM経由でインストールする必要があります。

npm install laravel-precognition-vue-inertia

インストールが完了すると、PrecognitionのuseForm関数は、上記で説明したバリデーション機能を備えたInertiaのフォームヘルパーを返します。

フォームヘルパーのsubmitメソッドは、HTTPメソッドやURLを指定する必要がなくなり、代わりにInertiaの訪問オプションを最初の引数として渡すことができます。また、submitメソッドは上記のVueの例で見られるようなPromiseを返しません。代わりに、submitメソッドに与えられた訪問オプションでInertiaがサポートするイベントコールバックを提供できます。

<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>

Reactを使用する

Laravel Precognitionを使用すると、バリデーションルールをフロントエンドのReactアプリケーションに複製することなく、ユーザーにライブバリデーションの体験を提供できます。どのように機能するかを説明するために、アプリケーション内で新しいユーザーを作成するためのフォームを構築しましょう。

まず、ルートにPrecognitionを有効にするために、HandlePrecognitiveRequestsミドルウェアをルート定義に追加する必要があります。また、ルートのバリデーションルールを格納するためのフォームリクエストを作成する必要があります。

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;

Route::post('/users', function (StoreUserRequest $request) {
    // ...
})->middleware([HandlePrecognitiveRequests::class]);

次に、Laravel PrecognitionのフロントエンドヘルパーをReact用にNPM経由でインストールします。

npm install laravel-precognition-react

Laravel Precognitionパッケージをインストールしたら、PrecognitionのuseForm関数を使用してフォームオブジェクトを作成できます。HTTPメソッド(post)、ターゲットURL(/users)、および初期フォームデータを提供します。

ライブバリデーションを有効にするために、各入力のchangeおよびblurイベントをリッスンする必要があります。changeイベントハンドラでは、setData関数を使用してフォームのデータを設定し、入力の名前と新しい値を渡します。次に、blurイベントハンドラでvalidateメソッドを呼び出し、入力の名前を渡します。

import { useForm } from 'laravel-precognition-react';

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

    const handleChange = (event) => {
        form.setData(event.target.name, event.target.value);
    };

    const handleBlur = (event) => {
        form.validate(event.target.name);
    };

    const handleSubmit = (event) => {
        event.preventDefault();
        form.submit();
    };

    return (
        <form onSubmit={handleSubmit}>
            <label htmlFor="name">Name</label>
            <input
                id="name"
                name="name"
                value={form.data.name}
                onChange={handleChange}
                onBlur={handleBlur}
            />
            {form.invalid('name') && <div>{form.errors.name}</div>}

            <label htmlFor="email">Email</label>
            <input
                id="email"
                name="email"
                type="email"
                value={form.data.email}
                onChange={handleChange}
                onBlur={handleBlur}
            />
            {form.invalid('email') && <div>{form.errors.email}</div>}

            <button type="submit" disabled={form.processing}>
                Create User
            </button>
        </form>
    );
}

Precognition

はじめに

Laravel Precognitionを使用すると、将来のHTTPリクエストの結果を予測することができます。Precognitionの主な用途の一つは、アプリケーションのバックエンドのバリデーションルールを複製することなく、フロントエンドのJavaScriptアプリケーションに「ライブ」バリデーションを提供することです。Precognitionは、特にLaravelのInertiaベースのスターターキットと組み合わせると効果的です。

Laravelが「予知リクエスト」を受け取ると、ルートのミドルウェアをすべて実行し、ルートのコントローラの依存関係を解決します。これには、フォームリクエストのバリデーションも含まれますが、実際にはルートのコントローラメソッドは実行されません。

ライブバリデーション

Vueを使用する

Laravel Precognitionを使用すると、バリデーションルールをフロントエンドのVueアプリケーションに複製することなく、ユーザーにライブバリデーションの体験を提供できます。どのように機能するかを説明するために、アプリケーション内で新しいユーザーを作成するためのフォームを構築しましょう。

まず、ルートにPrecognitionを有効にするために、HandlePrecognitiveRequestsミドルウェアをルート定義に追加する必要があります。また、ルートのバリデーションルールを格納するためのフォームリクエストを作成する必要があります。

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;

Route::post('/users', function (StoreUserRequest $request) {
    // ...
})->middleware([HandlePrecognitiveRequests::class]);

次に、Laravel PrecognitionのフロントエンドヘルパーをVue用にNPM経由でインストールします。

npm install laravel-precognition-vue

Laravel Precognitionパッケージをインストールしたら、PrecognitionのuseForm関数を使用してフォームオブジェクトを作成できます。HTTPメソッド(post)、ターゲットURL(/users)、および初期フォームデータを提供します。

次に、ライブバリデーションを有効にするために、各入力のchangeイベントでフォームのvalidateメソッドを呼び出し、入力の名前を渡します。

<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>

これで、ユーザーがフォームを入力すると、Precognitionはルートのフォームリクエストのバリデーションルールに基づいてライブバリデーションを提供します。フォームの入力が変更されると、デバウンスされた「予知」バリデーションリクエストがLaravelアプリケーションに送信されます。デバウンスタイムアウトは、フォームのsetValidationTimeout関数を呼び出して設定できます。

form.setValidationTimeout(3000);

バリデーションリクエストが進行中の場合、フォームのvalidatingプロパティはtrueになります。

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

バリデーションリクエスト中またはフォーム送信中に返されたバリデーションエラーは、自動的にフォームのerrorsオブジェクトに入力されます。

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

フォームにエラーがあるかどうかは、フォームのhasErrorsプロパティを使用して確認できます。

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

入力がバリデーションに合格したか失敗したかは、それぞれフォームのvalid関数とinvalid関数に入力の名前を渡すことで確認できます。

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

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

Warning

フォーム入力は、変更されてバリデーションレスポンスを受け取った後にのみ、有効または無効として表示されます。

Precognitionでフォームの入力のサブセットをバリデーションする場合、エラーを手動でクリアすると便利です。これは、フォームのforgetError関数を使用して行うことができます。

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

        form.forgetError('avatar')
    }"
>

これまで見てきたように、入力のchangeイベントにフックして、ユーザーが入力と対話するときに個々の入力をバリデーションすることができます。しかし、ユーザーがまだ対話していない入力をバリデーションする必要がある場合があります。これは、ユーザーが対話したかどうかに関係なく、すべての表示されている入力をバリデーションしたい「ウィザード」を構築する場合によくあります。

Precognitionでこれを行うには、バリデーションしたいフィールドを「touched」としてマークするために、それらの名前をtouchメソッドに渡します。次に、validateメソッドをonSuccessまたはonValidationErrorコールバックで呼び出します。

<button
    type="button" 
    @click="form.touch(['name', 'email', 'phone']).validate({
        onSuccess: (response) => nextStep(),
        onValidationError: (response) => /* ... */,
    })"
>Next Step</button>

もちろん、フォーム送信のレスポンスに反応してコードを実行することもできます。フォームのsubmit関数はAxiosリクエストのPromiseを返します。これにより、レスポンスペイロードにアクセスしたり、送信が成功した場合にフォーム入力をリセットしたり、リクエストが失敗した場合に対処したりする便利な方法が提供されます。

const submit = () => form.submit()
    .then(response => {
        form.reset();

        alert('User created.');
    })
    .catch(error => {
        alert('An error occurred.');
    });

フォーム送信リクエストが進行中かどうかは、フォームのprocessingプロパティを検査することで確認できます。

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

VueとInertiaを使用する

Note

VueとInertiaを使用してLaravelアプリケーションを開発する際にスタートアップをスムーズにしたい場合は、スターターキットのいずれかを使用することを検討してください。Laravelのスターターキットは、新しいLaravelアプリケーションのためのバックエンドとフロントエンドの認証スキャフォールディングを提供します。

PrecognitionをVueとInertiaで使用する前に、VueでPrecognitionを使用するに関する一般的なドキュメントを確認してください。VueとInertiaを使用する場合、Inertia互換のPrecognitionライブラリをNPM経由でインストールする必要があります。

npm install laravel-precognition-vue-inertia

インストールが完了すると、PrecognitionのuseForm関数は、上記で説明したバリデーション機能を備えたInertiaのフォームヘルパーを返します。

フォームヘルパーのsubmitメソッドは、HTTPメソッドやURLを指定する必要がなくなり、代わりにInertiaの訪問オプションを最初の引数として渡すことができます。また、submitメソッドは上記のVueの例で見られるようなPromiseを返しません。代わりに、submitメソッドに与えられた訪問オプションでInertiaがサポートするイベントコールバックを提供できます。

<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>

Reactを使用する

Laravel Precognitionを使用すると、バリデーションルールをフロントエンドのReactアプリケーションに複製することなく、ユーザーにライブバリデーションの体験を提供できます。どのように機能するかを説明するために、アプリケーション内で新しいユーザーを作成するためのフォームを構築しましょう。

まず、ルートにPrecognitionを有効にするために、HandlePrecognitiveRequestsミドルウェアをルート定義に追加する必要があります。また、ルートのバリデーションルールを格納するためのフォームリクエストを作成する必要があります。

use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;

Route::post('/users', function (StoreUserRequest $request) {
    // ...
})->middleware([HandlePrecognitiveRequests::class]);

次に、Laravel PrecognitionのフロントエンドヘルパーをReact用にNPM経由でインストールします。

npm install laravel-precognition-react

Laravel Precognitionパッケージをインストールしたら、PrecognitionのuseForm関数を使用してフォームオブジェクトを作成できます。HTTPメソッド(post)、ターゲットURL(/users)、および初期フォームデータを提供します。

ライブバリデーションを有効にするために、各入力のchangeおよびblurイベントをリッスンする必要があります。changeイベントハンドラでは、setData関数を使用してフォームのデータを設定し、入力の名前と新しい値を渡します。次に、blurイベントハンドラでvalidateメソッドを呼び出し、入力の名前を渡します。

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">名前</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">メールアドレス</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}>
                ユーザー作成
            </button>
        </form>
    );
};

ここで、ユーザーがフォームを入力すると、Precognitionはルートのフォームリクエスト内のバリデーションルールによって駆動されるライブバリデーション出力を提供します。フォームの入力が変更されると、デバウンスされた「予知」バリデーションリクエストがLaravelアプリケーションに送信されます。デバウンスタイムアウトは、フォームのsetValidationTimeout関数を呼び出すことで設定できます:

form.setValidationTimeout(3000);

バリデーションリクエストが進行中の場合、フォームのvalidatingプロパティはtrueになります:

{form.validating && <div>検証中...</div>}

バリデーションリクエストまたはフォーム送信中に返されるバリデーションエラーは、自動的にフォームのerrorsオブジェクトに格納されます:

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

フォームにエラーがあるかどうかは、フォームのhasErrorsプロパティを使用して確認できます:

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

また、入力がバリデーションに合格したか失敗したかを、それぞれフォームのvalid関数とinvalid関数に入力の名前を渡すことで確認できます:

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

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

Warning

フォーム入力は、変更されてバリデーションレスポンスが受信された後にのみ、有効または無効として表示されます。

Precognitionでフォームの入力のサブセットを検証する場合、エラーを手動でクリアすることが役立ちます。これは、フォームのforgetError関数を使用して行うことができます:

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

        form.forgetError('avatar');
    }}
>

ここまで見てきたように、入力のblurイベントにフックして、ユーザーが操作する際に個々の入力を検証することができます;ただし、ユーザーがまだ操作していない入力を検証する必要がある場合もあります。これは、ユーザーが次のステップに移動する前に、ユーザーが操作したかどうかに関係なく、すべての表示されている入力を検証したい「ウィザード」を構築する場合に一般的です。

これをPrecognitionで行うには、検証したいフィールドをtouchメソッドにそれらの名前を渡して「タッチ」としてマークする必要があります。そして、onSuccessまたはonValidationErrorコールバックを指定してvalidateメソッドを呼び出します:

<button
    type="button"
    onClick={() => form.touch(['name', 'email', 'phone']).validate({
        onSuccess: (response) => nextStep(),
        onValidationError: (response) => /* ... */,
    })}
>次のステップ</button>

もちろん、フォーム送信のレスポンスに反応してコードを実行することもできます。フォームのsubmit関数はAxiosリクエストのプロミスを返します。これにより、レスポンスペイロードにアクセスし、フォーム送信が成功した場合にフォームの入力をリセットしたり、リクエストが失敗した場合に処理する便利な方法が提供されます:

const submit = (e) => {
    e.preventDefault();

    form.submit()
        .then(response => {
            form.reset();

            alert('ユーザーが作成されました。');
        })
        .catch(error => {
            alert('エラーが発生しました。');
        });
};

フォーム送信リクエストが進行中かどうかは、フォームのprocessingプロパティを検査することで確認できます:

<button disabled={form.processing}>
    送信
</button>

ReactとInertiaを使用する

Note

LaravelアプリケーションをReactとInertiaで開発する際にスタートアップをスムーズにしたい場合は、スターターキットのいずれかを使用することを検討してください。Laravelのスターターキットは、新しいLaravelアプリケーションのためのバックエンドとフロントエンドの認証スキャフォールディングを提供します。

ReactとInertiaでPrecognitionを使用する前に、ReactでPrecognitionを使用するに関する一般的なドキュメントを確認してください。ReactとInertiaを使用する場合、Inertia互換のPrecognitionライブラリをNPM経由でインストールする必要があります:

npm install laravel-precognition-react-inertia

インストールが完了すると、PrecognitionのuseForm関数は、上記で説明したバリデーション機能を備えたInertiaのフォームヘルパーを返します。

フォームヘルパーのsubmitメソッドは、HTTPメソッドやURLを指定する必要がなくなり、代わりにInertiaの訪問オプションを最初の引数として渡すことができます。さらに、submitメソッドは、上記のReactの例のようにPromiseを返しません。代わりに、submitメソッドに指定された訪問オプション内で、Inertiaがサポートするイベントコールバックを提供できます:

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(),
    });
};

AlpineとBladeを使用する

Laravel Precognitionを使用すると、フロントエンドのAlpineアプリケーションでバリデーションルールを複製することなく、ユーザーにライブバリデーション体験を提供できます。その仕組みを説明するために、アプリケーション内で新しいユーザーを作成するためのフォームを構築しましょう。

まず、ルートのPrecognitionを有効にするために、HandlePrecognitiveRequestsミドルウェアをルート定義に追加する必要があります。また、ルートのバリデーションルールを格納するためのフォームリクエストを作成する必要があります:

use App\Http\Requests\CreateUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;

Route::post('/users', function (CreateUserRequest $request) {
    // ...
})->middleware([HandlePrecognitiveRequests::class]);

次に、Alpine用のLaravel PrecognitionフロントエンドヘルパーをNPM経由でインストールします:

npm install laravel-precognition-alpine

そして、resources/js/app.jsファイル内でAlpineにPrecognitionプラグインを登録します:

import Alpine from 'alpinejs';
import Precognition from 'laravel-precognition-alpine';

window.Alpine = Alpine;

Alpine.plugin(Precognition);
Alpine.start();

Laravel Precognitionパッケージがインストールされ、登録されたら、Precognitionの$form「マジック」を使用してフォームオブジェクトを作成できます。HTTPメソッド(post)、ターゲットURL(/users)、および初期フォームデータを提供します。

ライブバリデーションを有効にするには、フォームのデータを関連する入力にバインドし、各入力のchangeイベントをリッスンする必要があります。changeイベントハンドラで、入力の名前を指定してフォームのvalidateメソッドを呼び出す必要があります:

<form x-data="{
    form: $form('post', '/register', {
        name: '',
        email: '',
    }),
}">
    @csrf
    <label for="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">メールアドレス</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">
        ユーザー作成
    </button>
</form>

ここで、ユーザーがフォームを入力すると、Precognitionはルートのフォームリクエスト内のバリデーションルールによって駆動されるライブバリデーション出力を提供します。フォームの入力が変更されると、デバウンスされた「予知」バリデーションリクエストがLaravelアプリケーションに送信されます。デバウンスタイムアウトは、フォームのsetValidationTimeout関数を呼び出すことで設定できます:

form.setValidationTimeout(3000);

バリデーションリクエストが進行中の場合、フォームのvalidatingプロパティはtrueになります:

<template x-if="form.validating">
    <div>検証中...</div>
</template>

バリデーションリクエストまたはフォーム送信中に返されるバリデーションエラーは、自動的にフォームのerrorsオブジェクトに格納されます:

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

フォームにエラーがあるかどうかは、フォームのhasErrorsプロパティを使用して確認できます:

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

また、入力がバリデーションに合格したか失敗したかを、それぞれフォームのvalid関数とinvalid関数に入力の名前を渡すことで確認できます:

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

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

Warning

フォーム入力は、変更されてバリデーションレスポンスが受信された後にのみ、有効または無効として表示されます。

見てきたように、入力のchangeイベントにフックして、ユーザーが入力を操作するたびに個々の入力を検証することができます。しかし、ユーザーがまだ操作していない入力を検証する必要がある場合もあります。これは、ユーザーが次のステップに進む前に、ユーザーが操作したかどうかに関わらず、すべての表示されている入力を検証したい「ウィザード」を構築する際によくあることです。

Precognitionを使用してこれを行うには、検証したいフィールドを「触れた」状態にするために、それらの名前をtouchメソッドに渡す必要があります。その後、onSuccessまたはonValidationErrorコールバックを指定してvalidateメソッドを呼び出します。

<button
    type="button"
    @change="form.touch(['name', 'email', 'phone']).validate({
        onSuccess: (response) => nextStep(),
        onValidationError: (response) => /* ... */,
    })"
>次のステップ</button>

フォーム送信リクエストが処理中かどうかは、フォームのprocessingプロパティを調べることで判断できます。

<button :disabled="form.processing">
    送信
</button>

古いフォームデータの再入力

上記のユーザー作成の例では、Precognitionを使用してライブ検証を行っていますが、フォームの送信には従来のサーバーサイドのフォーム送信を行っています。そのため、サーバーサイドのフォーム送信から返された「古い」入力や検証エラーでフォームを再入力する必要があります。

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

または、XHRを介してフォームを送信したい場合は、フォームのsubmit関数を使用できます。これはAxiosリクエストのPromiseを返します。

<form
    x-data="{
        form: $form('post', '/register', {
            name: '',
            email: '',
        }),
        submit() {
            this.form.submit()
                .then(response => {
                    form.reset();

                    alert('ユーザーが作成されました。')
                })
                .catch(error => {
                    alert('エラーが発生しました。');
                });
        },
    }"
    @submit.prevent="submit"
>

Axiosの設定

Precognition検証ライブラリは、アプリケーションのバックエンドにリクエストを送信するためにAxios HTTPクライアントを使用します。便宜上、アプリケーションで必要な場合にAxiosインスタンスをカスタマイズすることができます。例えば、laravel-precognition-vueライブラリを使用している場合、アプリケーションのresources/js/app.jsファイルで各送信リクエストに追加のリクエストヘッダーを追加できます。

import { client } from 'laravel-precognition-vue';

client.axios().defaults.headers.common['Authorization'] = authToken;

または、アプリケーションに既に設定されたAxiosインスタンスがある場合、Precognitionにそのインスタンスを使用するよう指示できます。

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)

Warning

Inertiaを使用したPrecognitionライブラリは、検証リクエストに対してのみ設定されたAxiosインスタンスを使用します。フォーム送信は常にInertiaによって送信されます。

検証ルールのカスタマイズ

リクエストのisPrecognitiveメソッドを使用して、Precognitionリクエスト中に実行される検証ルールをカスタマイズすることができます。

例えば、ユーザー作成フォームでは、パスワードが「侵害されていない」ことを最終的なフォーム送信時にのみ検証したい場合があります。Precognition検証リクエストでは、パスワードが必須であり、最低8文字であることを検証します。isPrecognitiveメソッドを使用することで、フォームリクエストで定義されたルールをカスタマイズできます。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;

class StoreUserRequest extends FormRequest
{
    /**
     * リクエストに適用される検証ルールを取得します。
     *
     * @return array
     */
    protected function rules()
    {
        return [
            'password' => [
                'required',
                $this->isPrecognitive()
                    ? Password::min(8)
                    : Password::min(8)->uncompromised(),
            ],
            // ...
        ];
    }
}

ファイルアップロードの処理

デフォルトでは、Laravel PrecognitionはPrecognition検証リクエスト中にファイルをアップロードまたは検証しません。これにより、大きなファイルが不必要に複数回アップロードされることを防ぎます。

この動作のため、アプリケーションは対応するフォームリクエストの検証ルールをカスタマイズして、フィールドが完全なフォーム送信時にのみ必須であることを指定する必要があります。

/**
 * リクエストに適用される検証ルールを取得します。
 *
 * @return array
 */
protected function rules()
{
    return [
        'avatar' => [
            ...$this->isPrecognitive() ? [] : ['required'],
            'image',
            'mimes:jpg,png',
            'dimensions:ratio=3/2',
        ],
        // ...
    ];
}

すべての検証リクエストにファイルを含めたい場合は、クライアントサイドのフォームインスタンスでvalidateFiles関数を呼び出すことができます。

form.validateFiles();

副作用の管理

HandlePrecognitiveRequestsミドルウェアをルートに追加する際には、Precognitionリクエスト中にスキップすべき_他の_ミドルウェアに副作用があるかどうかを考慮する必要があります。

例えば、アプリケーションとのユーザーの「インタラクション」の総数を増やすミドルウェアがあるかもしれませんが、Precognitionリクエストをインタラクションとしてカウントしたくない場合があります。これを実現するために、リクエストのisPrecognitiveメソッドをチェックしてからインタラクションカウントを増やすことができます。

<?php

namespace App\Http\Middleware;

use App\Facades\Interaction;
use Closure;
use Illuminate\Http\Request;

class InteractionMiddleware
{
    /**
     * 受信リクエストを処理します。
     */
    public function handle(Request $request, Closure $next): mixed
    {
        if (! $request->isPrecognitive()) {
            Interaction::incrementFor($request->user());
        }

        return $next($request);
    }
}

テスト

テストでPrecognitionリクエストを行いたい場合、LaravelのTestCaseにはPrecognitionリクエストヘッダーを追加するwithPrecognitionヘルパーが含まれています。

さらに、Precognitionリクエストが成功したことをアサートしたい場合(例:検証エラーが返されなかった場合)、レスポンスのassertSuccessfulPrecognitionメソッドを使用できます。

it('validates registration form with precognition', function () {
    $response = $this->withPrecognition()
        ->post('/register', [
            'name' => 'Taylor Otwell',
        ]);

    $response->assertSuccessfulPrecognition();

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

    $response->assertSuccessfulPrecognition();
    $this->assertSame(0, User::count());
}

ユーザーノート