[Laravel8.46.0] 多言語(日・英・中国語)でバリデーションを切り分けて表示したい時

Laravelで多言語(日本語/中国語/英語)のアプリケーションを作っています。
ユーザのロールによって、販売画面は英語・中国語、管理画面は日本語・英語に切り分ける仕様。
その為、config/app.phpの localは英語(en)で設定します。

'locale' => 'en',

管理画面でユーザ登録や商品登録をしようとした時に、日本語のバリデーションを表示させたい。

### バリデーション(Request)作成
$ php artisan make:request CreateClientRequest

CreateClientRequest.php

public function rules()
    {
        return [
            'company' => ['required','max:100'],
            'name' => ['required','unique:users,name','min:2','max:24'],
            'lang' => ['required'],
            // 省略
        ];
    }

-> これだと、英語のバリデーションファイルを読みに行ってしまうので、日本語のバリデーションファイルを作ります。

/resources/lang/ja/validation.php

ここに日本語のvalidationを書きます。

return [
       // 省略
       'required' => ':attributeは必須です。',
       // 省略

    'attributes' => [
        'company'=>'会社名',
        'id'=>'ユーザID',
        'lang'=>'言語',
        // 省略
    ],
];

それで、CreateClientRequestで、この日本語のバリデーションを読み込むように、setlocaleで日本語を指定します。

CreateClientRequest.php

use Illuminate\Support\Facades\App;
    public function rules()
    {

        App::setLocale('ja');
        return [
            //
            'company' => ['required','max:100'],
            'name' => ['required','unique:users,name','min:2','max:24'],
            'lang' => ['required'],
            // 省略
        ];
    }

そうすると、このバリデーションでは、/ja/validation.phpを読みに行ってくれます。

App::setLocale(”); は、バリデーションファイル(Request)だけでなく、Controller側で指定しても、同じように、日本語のバリデーションファイルを読みにいきます。

つまり、config/app.phpで指定した言語以外のバリデーションも、App::setLocale(”)で自由に呼び出すことができるとういわけです。

うおおおおおおおおおおおおおお
俺がやりたかったのコレ。
久々にプログラミングで興奮した。

[Laravel8.x] エラーメッセージをモーダルで表示させたい

エラーメッセージをtextでも良いが、どちらかと言うとモーダルで表示させたい。

まず単純なフォームを作ります。

<body>
	@if(Session::has('flashmessage'))
    <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
      {{ session('flashmessage') }}
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
	@endif
	<form action="/admin/test/form/confirm" method="post">
		@csrf
	<p>
	名前:<input type="text" name="name" size="40">
	</p>
	<input type="submit" value="送信">
	</form>

<script
  src="https://code.jquery.com/jquery-3.5.1.js"
  integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
  crossorigin="anonymous"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script> -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script>
    // モーダルウィンドウ
    $(window).on('load',function(){
        $('#exampleModal').modal('show');
    });
</script>

controller

    public function testFormConfirm(Request $request){
        if($request->has('name') & $request->name !== NULL){
            session()->flash('flashmessage',$request->name. 'さん、登録完了');
        } else {
            session()->flash('flashmessage','エラー: 名前を入力してください');
        }

        return redirect('/admin/test/form');
    }

エラーのメッセージではなく、session flashで送るのか。なるほどね。

### 1冊やっておいても損はない本

[Laravel8.x] 半角英数字記号のバリデーションをmake:ruleで作る

IDやパスワードにalpha_dashを使おうとすると、日本語が通過してしまう。独自ルールを作る。

$ php artisan make:rule AlphaRule

app/Rules/AlphaRule.php

public function passes($attribute, $value)
    {
        //
        return preg_match('/^[!-~]+$/', $value);
    }

    public function message()
    {
        return ':attribute は半角英数字記号で入力してください';
    }

Request内で使用

use App\Rules\AlphaRule;

// 省略

'name' => ['required','unique:users,name','min:2','max:24',new AlphaRule],

->
ID は半角英数字記号で入力してください

これは実装が相当簡単

### 1冊やっておいても損はない本

[Laravel8.16.0] validationの:attributesの名前が重複する時

attributesでユーザ作成時にnameを「ユーザ名」と設定済みだが、商品登録時にnameを「商品名」と使いたい時。
-> requestの方で、attributeを設定すると、上書きされる。

resources/lang/ja/validation.php

'attributes' => [
        'name'=>'ユーザ名',
    ],

app/Http/Requests/CreateProductRequest.php

public function rules()
    {
        return [
            //
            'name' => ['required'],
        ];
    }

    public function attributes()
    {
        return [
            'name'           => '商品名',
        ];
    }

こうすると、商品登録時にnameでエラーとなった場合に、きちんと「商品名」で表示される。

なるほど、データベースの設計書も作成して作り始めてるのに、今更データベース側のカラム名を変更なんてやってられない。上手くできている。

[Laravel8.16.0] validationメソッド

まずフォームとcontrollerを用意します。

<form action="/admin/test" method="post">
		{{ csrf_field() }}
		<input type="text" name="name">
		<input type="submit" value="送信">
	</form>
public function test(Request $request){

        $validatedData = $request->validate([
            'name' => ['string'],
        ]);
        dd($validatedData);
    }

1. “string”のバリデーションで数字のみのチェックは通すか?

-> OK

2. minとmaxが同数の場合(桁数を指定)

        $validatedData = $request->validate([
            'name' => ['min:9','max:9'],
        ]);


-> OK

3. alpha_dashで数字のみ

-> OK

4. textareaで改行を含めた文字でpostした場合


-> ちゃんと”\r\n”で入ってますね。

OK、大体テストしたいことはテストできた。

[Laravel8.16.0] 電話と郵便番号のカスタムバリデーション作成

公式: https://readouble.com/laravel/8.x/ja/validation.html#custom-validation-rules

$ php artisan make:rule PhoneRule
app/Rules/PhoneRule.php

    public function passes($attribute, $value)
    {
        if($value){
           return preg_match('/^(([0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4})|([0-9]{8,11}))$/', $value);
       } else {
           return true;
       } 
    }
    public function message()
    {
        return trans('validation.phone');
    }

$ php artisan make:rule ZipcodeRule
app/Rules/ZipcodeRule.php

public function passes($attribute, $value)
    {
        if($value){
           return preg_match('/^(([0-9]{3}-[0-9]{4})|([0-9]{7}))$/', $value);
       } else {
           return true;
       } 
    }
    public function message()
    {
        return trans('validation.zipcode');
    }

/resources/lang/ja/validation.php

    'phone' => ':attributeはハイフン有りか無しで半角英数字8~11個の数字で入力してください。',
    'zipcode' => ':attributeはハイフン有りか無しで半角英数字7個の数字で入力してください。',

    'attributes' => [
        'phone'=>'電話番号',
        'zipcode'=>'郵便番号',
    ],

OK、次はEmail。HTML5のE-mailのバリデーションがどうなってるかだな。

### 1冊やっておいても損はない本

Laravel 入力フォームが時間・分に別れている時の未来判定バリデーション

– 入力フィールドが時間・分に別れている時に、「終了時間が開始時間より未来」のバリデーションルール作成方法
— どこで時間と分を結合してバリデーションをかけるか? 

*.blade.php

<tr>
                    <th>開始時刻 <span class="badge badge-danger">必須</span></th>
                    <td>
                        <div class="form-inline">
                                {!! Form::select('start_H', $hours, 10, ['class' => 'form-control']) !!}
                                <span class="unit">時</span>
                                {!! Form::select('start_i', $minutes, 1, ['class' => 'form-control']) !!}
                                <span class="unit">分</span>
                        </div>
                    </td>
                </tr>
                <tr>
                    <th>終了時刻 <span class="badge badge-danger">必須</span></th>
                    <td>
                        <div class="form-inline">
                                {!! Form::select('end_H', $hours, 19, ['class' => 'form-control']) !!}
                                <span class="unit">時</span>
                                {!! Form::select('end_i', $minutes, 1, ['class' => 'form-control']) !!}
                                <span class="unit">分</span>
                        </div>
                        @error('end')
                                <span class="error">{{$message}}</span>
                        @enderror
                    </td>
                </tr>

### controller
コントローラーでunix timeを計算し、「終了時間」-「開始時間」 <= 0 の時、withErrorsでエラーメッセージと一緒にredirect backする [php] public function confirm(CustomeRequest $request){ $inputs = $request->all();
$start = $inputs[‘start_H’] . ‘:’ . $inputs[‘remote_start_i’] . ‘:00’;
$end = $inputs[‘end_H’] . ‘:’ . $inputs[‘remote_end_i’] . ‘:00’;
if((strtotime($end) – strtotime($start)) <= 0) { return redirect()->back()->withInput()->withErrors(array(‘end’ => ‘終了時刻は、開始時刻より未来を設定してください’));
}
[/php]

フォームリクエストやカスタムリクエストは、attribute、バリデーション処理、エラーメッセージが対になっているので、コントローラー側で処理をした。

laravel 6.x nullableなフォームのカスタムバリデーションの作り方

– 電話番号のフォームに入力があった場合、電話番号のバリデーションをかけたい

/^(([0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4})|([0-9]{8,11})$/

– 未入力の場合はバリデーションをパスする

カスタムバリデーション公式ドキュメント: https://readouble.com/laravel/6.x/ja/validation.html#custom-validation-rules

$ php artisan make:rule PhoneRule

./app/Rules/PhoneRule.php
入力値がなかった場合は、tureを返す

 public function passes($attribute, $value)
    {
        if($value){
            return preg_match('/^(([0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4})|([0-9]{8,11}))$/', $value);
        } else {
            return true;
        }       
    }
    public function message()
    {
        return trans('validation.phone');
    }

./app/Http/Requests/CreateUserRequest.php

use App\Rules\PhoneRule;
public function rules()
    {
        return [
            'phone' => [new PhoneRule],
        ];
    }

./resources/lang/ja/validation.php

'phone' => ':attributeはハイフン有りか無しで半角英数字8~11個の数字で入力してください。',
'attributes' => [
        'phone'=>'電話番号',
    ],

コントローラーやRequestsにクロージャーでも書けるそうですが、コードの保守性を鑑みても、make:ruleとしてカスタムバリデーションを作った方が良さそうです。