Help us understand the problem. What is going on with this article?

Laravel/LumenでValidatorライブラリを作る

More than 1 year has passed since last update.

はじめに

アプリケーションが大きくなってくると、複数のリポジトリにまたがるライブラリを作りたくなってきます。
それをcomposer installで入れられたらもうダブルメンテなんて気にしなくて済みますよね。
ビジネスロジックに依存したバリデータは重複するものが多いので、わりとライブラリに切り出しやすかったりします。

Laravel/Lumenにはカスタムバリデータを簡単に作る機構があるのですが、それを独立したライブラリに切り出すのはちょっとコツが必要だったのでご紹介します。

(コツはここから

カスタムバリデータを定義する(どこにでも載ってる話)

まずライブラリのソース構成はこんな感じです。Composerのパッケージ定義等は割愛します。

src/
 ├ Providers/
 │   └ ValidatorServiceProvider.php
 └ Validators/
     └ NumberValidator.php

次にカスタムバリデータクラスを作成します。
1. Illuminate\Validation\Validatorを継承する
2. validateXXXという命名規則でバリデーションメソッドを定義する

use Illuminate\Validation\Validator;

class NumberValidator extends Validator
{
    public function validateNaturalNumber(string $attribute, $value, array $parameters, Validator $validator): bool
    {
        if ($validator->validateInteger($attribute, $value)) {
            return $value > 0;
        }
        return false;
    }
}

そしてバリデータをServiceProviderに登録します。

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use Relux\Validators\NumberValidator;

class ValidatorServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Validator::resolver(function ($translator, $data, $rules, $messages) {
            return new NumberValidator($translator, $data, $rules, $messages);
        });
    }
}

使うときはメソッド名をスネークケースにしたもので呼び出せます。

'required|natural_number'

ここまではどこにでも載っている話。

バリデーションメッセージをどこに定義するか

通常Laravel/Lumenのアプリケーションでバリデーションメッセージを定義する場合、下記のように言語ファイルを配置することでフレームワークが言語ファイルを読みに行ってくれます。

app/
 └ resources/
    └ lang/
       └ en/
          └ validation.php

ただ今回はComposerライブラリ内なので上記のような言語ファイル配置はできません。
でも同じようなことをライブラリでも実現したいと思い調べていると、こんな記述がありました。
https://laravel.com/docs/5.7/packages#translations

public function boot()
{
    $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
}

ServiceProviderでloadTranslationsFromを呼ぶことで言語ファイルを読み出すことができ、

echo trans('courier::messages.welcome');

という風にネームスペース付きで翻訳を呼び出すことができます。

最終的な実装はこうなった

src/
 ├ Providers/
 │   └ ValidatorServiceProvider.php
 ├ Validators/
 │   └ NumberValidator.php
 └ resources/
      └ lang/
         └ en/
            └ validation.php

ディレクトリ構成はLaravelと同じにしています。
validation.phpの中身は、通常の言語ファイルと同じようにただの連想配列。

return [
    'natural_number' => 'The :attribute must be natural number.',
];

ServiceProviderで言語ファイルの読み出しと、バリデータにメッセージをセットする。

class ValidatorServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // 言語ファイルをロード
        $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'Relux');

        // バリデーションメッセージを取得
        $customMessages = trans('Relux::validation');

        Validator::resolver(function ($translator, $data, $rules, $messages) use ($customMessages) {
            $validator = new NumberValidator($translator, $data, $rules, $messages);

            // バリデータにメッセージ群をセット
            $validator->setCustomMessages($customMessages);
            return $validator;
        });
    }
}

loadTranslationsFromはネームスペース付きで言語ファイルの内容を保持しています。
バリデータはネームスペースをもたせてバリデーションメッセージを取得しに行かないので、setCustomMessagesメソッドでメッセージリストを設定する必要があります。

ここにまだ課題があるので、バリデータがネームスペース付きでバリデーションメッセージを取得しに行くようにカスタマイズできないか考えてみたいです。

bengo4
「専門家をもっと身近に」を理念として、人々と専門家をつなぐポータルサイト「弁護士ドットコム」「弁護士ドットコムニュース」「税理士ドットコム」を提供。
https://corporate.bengo4.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした