vue.jsの{{}}が*.blade.phpでエラーになる時

{{}}がbladeの変数を受け渡す記述と同じなのでエラーになります。'{‘の頭に@を追加します。

### error

<span class="char-length">{{ message.length }}/20</span>

Use of undefined constant message – assumed ‘message’ (this will throw an Error in a future version of PHP)

### 修正

<span class="char-length">@{{ message.length }}/20</span>

これは比較的直ぐに原因がわかる類のエラーです。

Laravel 6.x 親テーブルに対し、複数のbelongsToで呼び込みたい時

親 :usersテーブル(->hasMany)、 子: pictures のリレーションにおいて、
子 picturesの 「user_id」 「review_user_id」 から、belongsToで親テーブルのユーザーを呼び込みたい時のモデルの書き方

### 子テーブルのmigration file

Schema::create('pictures', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id')->index()->unsigned();
            // 省略
            $table->integer('review_user_id')->index()->unsigned()->nullable();
            $table->timestamps();
            $table->softDeletes();
        });

### 子テーブルのモデル
Picture.php
belongsToの第二引数に小テーブルのカラム、第三引数に親テーブルのカラムを記述する。

public function user(){
        return $this->belongsTo('App\User');
    }
public function reviewUser(){
        return $this->belongsTo('App\User', 'review_user_id', 'id');
    }

### 挙動テスト

Route::get('/read', function(){
	// $user = Picture::findOrFail(1)->user;
	// dd($user);
	$user = Picture::findOrFail(2)->reviewUser;
	return $user->name;
});

直ぐに解決するかと思いきや、ドキュメントが少なく意外と苦戦しました。こういうケースでは、Laravel側としては、usersテーブルから2回呼び込むのではなく、users, review_usersという風に親テーブルを分けて設計して欲しいのかもしれません。

Laravel 確認画面でbelongsToの値を表示する

ユーザの権限テーブルを作り、ユーザ登録画面確認画面でデータベースのリレーションを使って権限テーブルから値を取得して表示させたい時

### usersテーブル作成

Schema::create('users', function (Blueprint $table) {
            // ...省略
            $table->integer('role_id')->index()->unsigned()->nullable();
            // 省略...
        });

### rolesテーブルの作成
$ php artisan make:model Role -m
migrationファイル

public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->timestamps();
        });
    }

$ php artisan migrate;
insert into roles (name) values (‘権限A’);
insert into roles (name) values (‘権限B’);

User.php

public function role(){
        return $this->belongsTo('App\Role');
    }

mass assignment
// 省略

### 登録画面
create.blade.php
– LaravelCollectiveでradioボタンを使って権限を選択する

<div class="form-check">
	            				{{Form::radio('role_id', 1, true, ['class' => 'form-check-input'])}}
	            				{!! Form::label('role_id', '権限A', ['class'=>'form-check-label']) !!}
            				</div>
            				<div class="form-check">
	            				{{Form::radio('role_id', 2, null, ['class' => 'form-check-input'])}}
	            				{!! Form::label('role_id', '権限B', ['class'=>'form-check-label']) !!}
            				</div>

### Controllerでの読み込み
UsersController.php
– plunkで、rolesテーブルのidとnameを配列で取得して、入力値と一緒にviewに渡す

use App\Role;
public function confirm(Request $request)
    {
        $roles = Role::pluck('name','id')->all();
        $inputs = $request->all();
        return view('admin.account.confirm', compact('inputs','roles'));
    }

### 確認画面での表示
confirm.blade.php
– 入力画面から渡ってきたrolesテーブルのrole_idの値を表示

{{ $roles[$inputs['role_id']] }}

laravel 6.x 確認画面を挟んだstorage画像の保存処理

Laravelでは画像はstorageフォルダに格納する
Webからのアクセスを許すには、public/storageからstorage/app/publicへシンボリックリンクを張る必要がある
https://readouble.com/laravel/6.x/ja/filesystem.html

### 駄目な例
moveコマンドで、public配下に格納

UsersController.php

if($file = $request->file('file')){
            $name = $file->getClientOriginalName();
            $file->move('./images/tmp/', $name);
            $inputs['path'] = $name;

### 格納先・読み込み元をstorageに修正
$ php artisan storage:link
// ./public/storageが./storage/app/publicへのリンクとなる

UsersController.php

if($file = $request->file('file')){
            $name = $file->getClientOriginalName();
            // $file->move('./images/tmp/', $name);
            $file->storeAs('./public/images/tmp/', $name);
            $inputs['path'] = $name;

confirm.blade.php

<img src="{{ $inputs&#91;'path'&#93; ? asset('/storage/images/tmp/' . $inputs&#91;'path'&#93;) : 'https://placehold.jp/100x100.png' }}" class="img-icon">

確認画面で戻るボタンが押された場合は、Storage::deleteで削除する。確認画面で登録完了ボタンが押された場合は、画像の前部にCarbonでtimestampを付けて、prdフォルダに移動させる。画像のpathはDBに格納する。

UsersController.php

use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;
public function store(Request $request)
    {
        $action = $request->get('action');
        $inputs = $request->except('action');

        if($action == '戻る'){
            Storage::delete('public/images/tmp/'.$inputs['profile_img']);
            return redirect()->action('UsersController@create')->withInput($inputs);
        }
        $timestamp = Carbon::now()->timestamp;
        $path = $timestamp.'_'.$inputs['profile_img'];
        Storage::move('public/images/tmp/'.$inputs['profile_img'], 'public/images/prd/'.$path);
        return 'done';
    }

ドキュメントを読む限り、storageに格納した方がファイルシステムの使う上で都合が良いように見えます。

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としてカスタムバリデーションを作った方が良さそうです。

画像バリデーションにおけるbmp、SVG、webpの扱い

### 画像バリデーションの拡張子
一昔前は、画像の拡張子といえば、jpeg,jpg,gif,pngのみが多かった印象がありますが(自分だけ?)、Laravel6.xのimageのバリデーションでは「jpg、png、bmp、gif、svg、webp」となっております。そのまま、jpeg,jpg,gif,pngに加えて、bmp,svg, webpも採用するかについて考えたいと思います。

### SVGとは?
SVGとは、Scalable Vector Graphicsの略です。
名称からどのような画像かほぼ想像がつきますが、念の為コードを書きながら特徴を見てみましょう。

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="40" y="40" width="80" height="80" fill="tomato"/>
	</svg>

### view box

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="40" y="40" width="80" height="80" fill="tomato"/>
	</svg>
	<svg width="160" height="160" viewBox="0 0 320 320">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="40" y="40" width="80" height="80" fill="tomato"/>
	</svg>

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="20" y="20" width="30" height="30" fill="#08c"/>
		<rect x="65" y="20" width="30" height="30" fill="rgb(255, 0, 0, 4)"/>
		<rect x="110" y="20" width="30" height="30" fill="hsla(120, 40%, 40%, .4)"/>
	</svg>

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="20" y="20" width="30" height="30" fill="#08c"/>
		<rect x="65" y="20" width="30" height="30" fill="rgb(255, 0, 0, 4)"/>
		<rect x="110" y="20" width="30" height="30" fill="hsla(120, 40%, 40%, .4)"/>
		<rect x="20" y="65" width="30" height="30" fill="none" stroke="olive" stroke-width="2"/>
		<rect x="65" y="65" width="30" height="30" fill="none" stroke="olive" stroke-dasharray="10"/>
		<rect x="110" y="65" width="30" height="30" fill="none" stroke="olive" stroke-width="2" stroke-dasharray="10, 2"/>
	</svg>

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="20" y="20" width="30" height="30" style="fill:#08c; stroke:#eee; stroke-width:3;"/>
	</svg>

<svg width="160" height="160">
		<defs>
			<style>
				.my-box {
					fill: pink;
				}
			</style>
		</defs>
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<rect x="20" y="20" width="30" height="30" style="fill:#08c; stroke:#eee; stroke-width:3;"/>
		<rect x="60" y="20" width="30" height="30" class="my-box"/>
	</svg>

<svg width="160" height="160">
		<rect x="0" y="0" width="160" height="160" fill="skyblue"/>
		<circle cx="80" cy="80" r="40" fill="gold" />
	</svg>	

### Photoshop、IllustratorのSVG、bmpの扱い
photoshopではbmpはありますが、SVGはありません。

一方、ベクターなのでIllustratorはSVGの取り扱いがあります。

### 結論
卒業写真など、オフィシャルなものであれば写真オンリーでしょうが、compassなどを見るとjpegの写真は殆どの見ないくらい写真以外をプロフィール画像にすることは浸透しているため、bmp,svg, webpもバリデーションに加えて良いでしょう。

プログラミングの義務教育が始まるので、近い未来、卒業写真にベクター画像を載せる学校が出てくるかもしれませんね。

jpeg/gif/bmp/svg

jpeg: Joint Photographic Experts Group, 24bit 1670万色, 1/10〜1/50圧縮率
gif: Graphic Interchange Format, 8bit 256色、高圧縮可能、ファイルサイズが小さい、ロゴ・ボタン・アイコンなど
png: Portable Network Graphic, 48bit, 280兆色、可逆圧縮、画質劣化がない、透明・不透明・半透明対応
bmp: Microsoft Windows Bitmap Image, 無圧縮、データが大きい
svg: Scalable Vector Graphics, XMLベースの2次元ベクターイメージ

jpg

gif

png

bmp
-> not permitted in wordpress

svgは割と最近使われていると言われているので、基礎は勉強する必要がありそうです。

Laravel6.x バリデーションのエラーメッセージを日本語化

### 初期(デフォルト)のメッセージ
./config/app.php

'locale' => 'ja',

$ php artisan make:request CreateUserRequest
CreateUserRequest.php

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

UsersController.php

public function confirm(CreateUserRequest $request)
    {
        return $request->all();
    }

view.blade.php

@if ($errors->has('name'))
  <br><span class="error">{{ $errors->first('name') }}</span>
@endif

エラーメッセージ
validation.required

### 英語のメッセージを複製
./resources/lang/ja/validation.php を作成
./resources/lang/en/validation.php の内容を ja/validation.php に複製

エラーメッセージ
The name field is required.

### 日本語メッセージにカスタマイズ
./resources/lang/ja/validation.php

'required' => ':attributeは必須です。',
'attributes' => [
        'last_name'=>'名前',
    ],

エラーメッセージ
名前は必須です。

バリデーションの仕様、メッセージに関しては、Wiki・Excelなどでステークホルダー全員で共有しながら管理することが多いでしょう。大規模なアプリケーションになるとバリデーションの数も増えてくるので、管理方法も工夫したい。

ruby install

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ echo ‘export PATH=”$HOME/.rbenv/bin:$PATH”‘ >> ~/.bash_profile
$ echo ‘eval “$(rbenv init -)”‘ >> ~/.bash_profile
$ source ~/.bash_profile

$ rbenv install –list
$ rbenv install 2.7.0
$ rbenv global 2.7.0
$ rbenv rehash

$ which ruby
$ ruby –version

$ sudo yum install rubygems
$ gem update –system 2.7.10

linux timezone変更手順

$ date
$ cat /etc/localtime
TZif2UTCTZif2?UTC
UTC0
$ sudo cp /etc/localtime /etc/localtime.org
$ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ sudo cp /etc/sysconfig/clock /etc/sysconfig/clock.org
$ sudo vi /etc/sysconfig/clock

ZONE="Asia/Tokyo"
UTC=false

$ strings /etc/localtime
$ date