かきスタンプ

福岡でフリーランスの物流系のエンジニアやってます。

Laravel : $this->validate にて、カスタムメッセージを使用する

Laravel でバリデーションをする時、FormRequest を継承したクラスを定義しなくても、コントローラに以下のように書く事でバリデーションができます。

FormRequest を使うほどの汎用性もボリュームもない場合は、この方法でも良いのではないでしょうか。

    $this->validate(
        $request,
        [
            'title' => 'required|min:3',
            'body'  => 'required'
        ],
    );

エラーメッセージをカスタマイズしたい場合、フォームリクエストを使用したときは messages() メソッドにその内容を書いていくけど、この場合はどうすれば?
と思って調べてみた。

単に、validate の第2引数に、メッセージの内容を渡すだけでOKです。

    $this->validate(
        $request,
        [
            'title' => 'required|min:3',
            'body'  => 'required'
        ],
        [
            'title.required' => 'please enter title.',
            'body.required'  => 'please enter body.'
        ]
    );

Validatorファサードを使用する場合、こんな感じ。

      \Validator::make($request->all(),
          [
              'title' => 'required|min:3',
              'body' => 'required',
          ],
          [
              'title.required' => 'please enter title.',
              'body.required'  => 'please enter body.'
          ]
      )->validate();

PHP:JSON エンコードした時に「/」が「\/」になる挙動を回避

通常、json_encode した場合、「/」は「\/」にエスケープされます。

$array_data = [
    'message' => 'Please register as /regist_users',
];

echo json_encode($array_data);
//=> {"message":"Please register as \/regist_users"}

エスケープさせず、そのまま「/」を表示したい場合、JSON_UNESCAPED_SLASHES オプションを使います。

$array_data = [
    'message' => 'Please register as /regist_users',
];


echo json_encode($array_data, JSON_UNESCAPED_SLASHES);
//=> {"message":"Please register as /regist_users"}

 
 


<参考>
https://www.php.net/manual/ja/function.json-encode.php
https://www.php.net/manual/ja/json.constants.php

PHP:ファイルを読み込む関数の使い分け(file, fopen, readfile, file_get_contents)

PHP:ファイルを読み込む関数の使い分け(file, fopen, readfile, file_get_contents)

PHPでファイルを読み込むビルトイン関数は、結構色々あります。

  • file
  • fopen
  • readfile
  • file_get_contents

等。

以下の条件によって、使い分けをしていけばよいのではないでしょうか。

  • テキストか、バイナリか
  • ファイルサイズ
  • どんな使い方をするのか

という訳で、以下、各関数について。

file

https://www.php.net/manual/en/function.file.php

テキストファイル限定。(改行コードを区切り文字として使うため。)
すべてを変数(メモリ)に一旦貯めるので、あまりにも大きいファイルの使用には向かない。

ファイルの中身が配列になる。
改行区切りのテキストファイルを扱うのに適している。

使用例
// ファイルの内容を配列に取り込みます。
$file = file(__FILE__);

// 行単位で出力
foreach ($file as $lines => $line) {
    echo "Line #{$line_num} : " . htmlspecialchars($line);
}

fopen

https://www.php.net/manual/ja/function.fopen.php

テキスト・バイナリどちらでも使える。
ファイルの大小に関係なく使用可。

自身で色々制御する際に使う。

使用例
// ファイルを開く(戻り値は、FilePointer と呼ばれる特殊な変数)
$handle = fopen(__FILE__, "r");  // readonly

// ファイル内容を出力
while ($line = fgets($handle)) {
  echo $line;
}
// ファイルポインタをクローズ
fclose($handle);

readfile

https://www.php.net/manual/ja/function.readfile.php

テキスト・バイナリどちらでも使える。
巨大なファイルでも使用可。(詳細は上記リンクを参照)

ファイルの中身をそのまま表示する。
何かしらの制御を加えたいなら、別のを使った方がいいかも。

使用例
readfile(__FILE__);     // コンソールに、このファイルの内容が出てくる

file_get_contens

https://www.php.net/manual/ja/function.file-get-contents.php

テキスト・バイナリどちらでも使える。
file と同じ理由で、あまりにも大きいファイルの使用には向かない。

使用例
$current = file_get_contents(__FILE__);

print_r($current);

引数に URLを使用すると、GETリクエストとして使用可。
というか、そっちの使い方しかしてない人も多いかもしんない。
パラメータ次第で PUTにする・パラメータを渡す・SSLエラーを無視する、といった HTTPリクエストライブラリと同様に使う事が出来なくはない。

その他

xml ファイルを読むときは simplexml_load_file を、
ini ファイルを読むとき parse_ini_file を使えばいいんじゃないかと思います。

間違ってたら、ご指摘いただけると助かります。

VSCode、Laravel : Undefined type 'Route' のエラーメッセージを消す方法

Visual Studio CodePHP IntelliSense プラグインを入れて Laravel を触ってると、下部に赤線が入って、こんなエラーメッセージが発生する。
(2020年 4月時点)

f:id:kakisoft:20200502214230p:plain

Undefined type 'Route' . Intephense

設定変更でエラーメッセージを消す事ができます。

ー1ー

プラグインPHP IntelliSense」表示し、「Extention Setting」 を選択。
f:id:kakisoft:20200502214319p:plain

ー2ー

入力欄に、「 intelephense.diagnostics.undefinedTypes 」と入力。
チェックを OFF にする。
f:id:kakisoft:20200502214340p:plain

ー3ー

Visual Studio Code を再起動。
こんな感じで、エラーメッセージが消えます。
f:id:kakisoft:20200502214355p:plain


<参考サイト>
https://github.com/bmewburn/vscode-intelephense/issues/780

PHP:エルビス演算子【(expr1) ? (expr2) : (expr3) 】と、Null合体演算子【(expr1) ?? (expr2)】は、「??」を使った方が無難かも。

とてもよく似ている以下の2つの演算子

主な違いは以下の点でしょうか。

  • ? は、「0」「"0"」「空の配列」を false と判定し、右辺の値を返す
  • ?? は、「0」「"0"」「空の配列」を true と判定し、その値を返す

0 や "0" を、「値がセットされていない状態」として扱うかどうかはシステムによって変わってくると思うので、これらを初期値に置き換えない Null合体演算子(??)を使った方が、予期せぬ不具合を起こしにくいのでは?
という話。
 
以下、構文の説明と実行結果。
PHP ver 7.1.32 で実行しています。

エルビス演算子

https://www.php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.ternary

(expr1) ? (expr2) : (expr3)
 
expr1 が TRUE の場合に expr2 を、 expr1 が FALSE の場合に expr3 を値とする。
 
式 expr1 ?: expr3 の結果は、expr1 が TRUE と同等の場合は expr1、 それ以外の場合は expr3 となります。

実行結果

var_dump(     "a" ? "a"     : "not_exists" );  //=> "a"
var_dump(     "0" ? "0"     : "not_exists" );  //=> "not_exists"
var_dump(   "0.0" ? "0.0"   : "not_exists" );  //=> "0.0"
var_dump(  "0x00" ? "0x00"  : "not_exists" );  //=> "0x00"
var_dump(       0 ? 0       : "not_exists" );  //=> "not_exists"
var_dump(     0.0 ? 0.0     : "not_exists" );  //=> "not_exists"
var_dump(    0x00 ? 0x00    : "not_exists" );  //=> "not_exists"
var_dump( array() ? array() : "not_exists" );  //=> "not_exists"
var_dump(    NULL ? NULL    : "not_exists" );  //=> "not_exists"
var_dump(   FALSE ? FALSE   : "not_exists" );  //=> "not_exists"
var_dump( $undefined_variable ? $undefined_variable : 'not_exists' );  //=> "not_exists"  ※Noticeが出る

"0" は false で、"0.0" が true というのが、何だかややこしい。

Null 合体演算子(7~)

https://www.php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.coalesce

式 (expr1) ?? (expr2) は、
expr1 が NULL である場合は expr2 と評価され、
それ以外の場合は expr1 と評価されます。

実行結果

var_dump(     "a" ?? "not_exists" );  //=> "a"
var_dump(     "0" ?? "not_exists" );  //=> "0"
var_dump(   "0.0" ?? "not_exists" );  //=> "0.0"
var_dump(  "0x00" ?? "not_exists" );  //=> "0x00"
var_dump(       0 ?? "not_exists" );  //=> 0
var_dump(     0.0 ?? "not_exists" );  //=> 0
var_dump(    0x00 ?? "not_exists" );  //=> 0
var_dump( array() ?? "not_exists" );  //=> array(0) {}
var_dump(    NULL ?? "not_exists" );  //=> "not_exists"
var_dump(   FALSE ?? "not_exists" );  //=> "not_exists"
var_dump( $undefined_variable  ?? "not_exists" );  //=> "not_exists"  ※Noticeが出ない

こっちは "0" も "0.0" も true。

jQuery:無効化したセレクトボックスの値を送信する方法

深淵な事情があり、

「セレクトボックスで表示している内容があるが、その項目はユーザから直接操作できないようにする。その部分をテキストボックス(ReadOnly)とかに置き換えると影響範囲がめっさ広がるんで、部品を変えずに何とかする。」

というロジックを入れる事になった。

セレクトボックスには ReadOnly属性が無いな。どうするべ。
と悩んで、取った手段がこんな感じ。

実装

「セレクトボックスのイベントを発生させない」という方法で対処しました。

HTML
<select id="my-select-01">
    <option>value01</option>
    <option>value02</option>
    <option>value03</option>
</select>

<input type="submit" id="my-submit-01">
JavaScript
jQuery(document).ready(function($) {

    $('#my-select-01').on('selectstart', false)
    $('#my-select-01').on('contextmenu', false)
    $('#my-select-01').on('keydown', false)
    $('#my-select-01').on('mousedown', false);

}

セレクトボックスを押しても選択内容を表示しないように、イベントをキャンセル。

上記のような問題を解決してくれるプラグインがあるみたいですが、やってる事は結局上記で書いてるような事なので、
「使うはどうせここだけだし、わざわざプラグインとして追加するほどの事でもなくね?」と思って、この方法にした。

<参考サイト>

セレクトボックスを変更できないよう固定してかつ値も送信するjQueryプラグイン
query-selection


没案

「セレクトボックスを無効化し、送信直前に有効化」
という方法を最初に考えたのですが、最終的には不採用となりました。
理由は、IE では上手く動かなかったため。
 
念のため、書いとく。

HTML
<select id="my-select-01" disabled>
    <option>value01</option>
    <option>value02</option>
    <option>value03</option>
</select>

<input type="submit" id="my-submit-01">
JavaScript
    // 送信時にセレクトボックスを有効化する
    $("#my-submit-01").on('click', function() {
        $("#my-select-01").prop("disabled", false);
    });

disabled にして操作を無効化。
そのままだと値が submit されないので、送信直前に disabled を取り外す、というやり方。

<input type="number"> は、凄く変な動きをするので、結局使わなかった話

※ 2020年 3月 9日時点の内容です
 
<ブラウザ>
Chrome : バージョン 80.0.3987.122

HTML5 で追加された、<input type="number"> の挙動が物凄い微妙だったので、結局使わなかった。
 
こういうの。
f:id:kakisoft:20200309014949p:plain

<input type="number">

数値のみを許可し、数値を上下させるボタンが付いている。

以下、その理由。

アルファベットの「e」が入力可能

パッと触ってみた感じ、数字しか入力できないように制御されているかと思いきや、アルファベットの e が入力できる。
指数の入力に対応したという事なのかもしれないが、嬉しい場面あるのか? これ。
ブラウザを使う大多数の人間は数学とは無縁の人だし、指数入力をする場面が多く存在するとは全く思えん。

つーか、「数値の入力のみを許可する」という仕様に対し、「e」が入力できたとしたら 99.9% バグ扱いされると思う。
「指数の入力に対応してます!」と言ったところで、「いや、そんなの使わねーから!」と却下されるんじゃないのか。

pattern が使えない

というわけで、アルファベットの「e」の入力を不許可にするべく、pattern で制御してしまおう。

<input type="number" pattern="^\d+$">

これで「e」の入力制限ができる・・・かと思いきや、input type="number" の時は、pattern はサポートされないらしい。
公式にもちゃんと書いてある。

何てこった。
という事で、こんな感じで対処。

<input type=number oninput="value=value.replace(/^\d/g, '')">

この時点でテンションがダダ下がり。
というか何でわざわざ正規表現を使って制御しなければならんのだ。開発者サイドでこういう気を回したく無いから使ってるのに。

小数の扱いが微妙

小数点がかなり適当に打ててしまう。
f:id:kakisoft:20200309015032p:plain
こんな感じで、先頭に小数点を入れたり、小数点を連続で入力できたり、末尾に数字を入れずに入力できたりする。
submit で弾けるとはいえ、こういう入力できるのはあんまりだ。
 
という事で、onchange で value を評価して、不正な値だったら整形・・・とやりたかったが、うまく動かない。
value をトレースすると、入力が「3.」なら valueは「3」となってたり、入力が「3..4」なら value は空白だったりと、小数点を取ることができなかったりする。
もう何を意図してそんな値にしたのか、さっぱり分からない。
 
解決するにはDOM操作でやらないといけないの? いやいや、そこまでして使いたく無いよ。

FireFox での挙動ががが

FireFox : バージョン 73.0.1
 
何と、全角数字の入力ができちゃうぜ! 数値だけじゃなくて日本語も入力可能だ!
一応、値はちゃんと取れるが、例のごとく pattern での入力制限ができない。

結論

<input type="number"> は、挙動が微妙すぎるんで、使わない方がいいんじゃないかな。