Laravel – 複数のsubmitボタン

概要

Laravelで1つのフォームに複数のsubmitボタンを配置して、押されたボタンによって処理を分ける方法。

  • ボタンにname属性を加える
  • アクションのRequest引数のhasメソッドで、引数にname属性の値を指定して、それらに応じた処理を記述する

以下のフォームを含むビューを準備する。

コントローラーに以下のアクションを準備し、フォームからのPOSTに対してルーティング設定する。

ボタン1/ボタン2を押すと、それぞれのname属性の値に応じたメッセージが表示される。

 

Laravel – バリデーション – validate()

概要

Laravelにおけるフォーム入力のバリデーションのうち、validate()メソッドによる手順を整理する。

検証ルールの詳細については別途整理している。

コード例

ビュー

以下のビューで入力と入力結果の表示を兼用。

コントローラー

GETに対するアクションは、単にビューを表示するだけ。

フォームからのPOSTに対するアクションは、ユーザー名、ハンドルネーム、メールアドレスの3つの入力を受け取り、下部にそれを表示する。タイトル表示で入力結果を表示していることが判別できる。

条件の設定

基本形

検証条件設定の基本形は以下のとおり。検証条件の詳細はこちらを参照。

  • アクションの引数のRequestインスタンスのvalidate()メソッドで設定
  • 条件は連想配列でvalidate()の引数に渡す
  • 連想配列のキー文字列がフォームの各アイテムのname属性値
  • キーに対応する値が各アイテムに対する条件で、文字列で設定

$request->validate(['name属性' => '検証条件']);

複数条件

1つのアイテムに複数の条件があるときの設定方法には2つある。

配列にする方法

検証条件の文字列を要素とする配列を値とする。

$request->validate(['name属性' => ['検証条件1', '検証条件2', ...]]);

文字列内で'|'でつなぐ方法

検証条件をOR演算子と同じ'|'でつないだ文字列を値として渡す。

$request->validate(['name属性' => '検証条件1|検証条件2|...']);

検証結果に応じた処理

処理の流れ

検証結果が妥当な場合は、そのまま以降の処理が実行される。検証結果の1つ以上が妥当でなければ、validate()メソッドより後は実行されず、元の画面がレンダリングされる。

先のコードで、すべての条件が妥当なら、タイトルが「バリデーションサンプル結果」となり入力内容が表示される。一方、条件の何れか1つでも妥当でなければ、タイトルは「バリデーションサンプル入力」となり入力内容は表示されない。

$errors

バリデーションの結果が妥当でない場合、グローバル変数$errorsにメッセージが保存される。$errorsViewErrorBagクラスのオブジェクトで、以下の様にすることで各エラーメッセージを順次取り出すことができる(エラーがない場合は処理されない)。

foreach ($errors->all() as $error)

以下は$errorsの内容をビューに表示させる例。コントローラーで特に定義等の必要はなく、検証結果に応じてセットされる。

たとえばユーザーネームを空にし、ハンドルネームに11文字、メールアドレスに@マークなしの文字列を入れた場合の$errorsの表示例は以下のとおり。

The name field is required.

The handlename may not be greater than 10 characters.

The email format is invalid.

フォームリクエスト

ここではコントローラーにバリデーション処理を記述したが、フォームリクエストを利用することによってこれを分離できる。

また、フォームリクエストのメソッドをオーバーライドして、エラーメッセージをカスタマイズすることもできる。

参考:Laravel 6.x バリデーション~エラーメッセージのカスタマイズ

 

Laravel – validation – 検証ルール

概要

主なバリデーションルールを整理する。網羅的な内容はドキュメントを参照。

存在・唯一性

required

パラメーターが入力されているか。

required

unique

データベースの指定フィールド内で唯一か。

unique

サイズ

size/min/max/between

フィールドの種類に応じて、特定値、最小値・最大値、値の範囲を検証。

size:サイズ
min:最小サイズ
max:最大サイズ
between:最小サイズ,最大サイズ

サイズはフィールドの種類によって解釈。

  • 文字列の場合は文字数
  • 数値の場合は整数値
  • ファイルの場合はキロバイト単位のファイルサイズ

正規表現

regex

入力が正規表現パターンに一致するかどうか。

regex:/正規表現/

数値形式

integer/numeric

入力が整数か/数値か

digits/digits_between

桁数が合致しているか/範囲内か。

digits:桁数
digits_between:最小桁数,最大桁数

文字列形式

string

入力が文字列かどうか。

string

email/url/active_url/ip

e-mailアドレス形式、URL形式か/有効なURLか、IPアドレス形式か。

email
url
active_url
ip

json

JSON文字列か。

json

timezone

タイムゾーンの文字列か。

timezone

日付

date

日付かどうか。日付の存在チェックも行う。たとえば2020/2/29は妥当だが、2021/2/29はエラーとなる。

date

date_format

指定した日付・時刻フォーマットか(YYYY/MM/ddH:iなど)。

date:日付・時刻フォーマット

before/after

指定した日付より前か/後か。現在を基準にする場合はnow

before:now
after:2020-3-31

before_or_equal/after_or_equal

指定した日付以前か/以後か。

before_or_equal:now
after_or_equal:2020-3-31

ファイル確認

file/image

ファイルかどうか。

file

画像ファイル(jpg,png,bmp,gif,svg)かどうか。

image

mimes

指定した拡張子か。

mimes:拡張子,拡張子,...

dimensions

画像パラメーターが指定した値か。

dimensions:属性=値,属性=値,...

属性の種類はmin_widthmax_widthmin_heightwidthheightratio

 

PHP – テキスト – 読み込み – SplFileObject

概要

Standard PHP LibraryのSplFileObjectを使ったテキストファイルの読み込みについて整理する。

  • ファイル名を指定してSplFileObjectのインスタンスを生成
    • $file = new \SplFileObject('textファイルパス');
    • $open_modeはデフォルト値の'r'(読み込み)
  • テキスト読み込みのためのフラグをセット
    • $file.setFlags(...);
  • ファイルを読み込み
    • foreachで行単位データを取得

なお、Splは”Standard PHP Library”の略。

基本例

例として、GETリクエストに応じて所定の場所に配置されたテキストファイルを読みだし、その内容を行データを要素とする配列に格納し、dd()で表示させてみる。

CSVファイルの配置

storage/app/ディレクトリーにテキストファイルを配置した場合は、storage_path()関数にstorageディレクトリーを基準としたパスを指定してフルパスを得ることができる。

たとえば以下の内容のファイルをstorage/app/text_sample_utf8.csvとして配置する(エンコーディングはUTF-8)。

コントローラー

テキストファイルを読み込み、その内容を配列に保存してdd()で表示するアクションは以下のとおり。

dd()の表示結果は以下の通り。

フラグ

空行を読み飛ばしたい場合は、READ_AHEADSKIP_EMPTYDROP_NEW_LINEの3つを設定する。空行を空の文字列として確保したい場合は最後の空行の要不要をによって、不要ならデータを削除する。

詳細はこちらを参照。

 

PHP – SplFileObject::setFrags()

概要

PHPのSplFileObjectのフラグがわかりにくかったので整理した。確認したバージョンは以下の通り。

  • OS: Vagrant/VirtualBox/CentOS7
  • PHP: 7.3.28
  • Laravel: 6.20.29

フラグ詳細

\SplFileObject::READ_CSV

行読込の際、CSV列として解釈する。
\SplFileObject::READ_AHEAD
日本語・英語のどのサイトでもマニュアル記述そのままに”先読み/巻き戻しで読み込む”としか書いていない。SKIP_EMPTYなどの処理のためにバッファリングして、処理が行われた場合に巻き戻すという意味か。
\SplFileObject::SKIP_EMPTY
空行が無視される。改行コードのみの行は空行とは認識されず削除対象とならないが、DROP_NEW_LINEと組み合わせることで空行がスキップされる。
\SplFileObject::DROP_NEW_LINE
改行文字が無視される。ダブルクォートで囲んだ項目中に改行文字がある場合も、改行文字が削除される。たとえば以下の様にフィールドの途中に改行を入れたり、空行がある場合、DROP_NEW_LINEにより宮城県と仙台市の間の改行が除かれ、”宮城県仙台市”とつなげられる

テキストファイル読み込み時

概要

以下のようにテキストファイルを扱いたい場合。

  • 改行コードは取り除きたい
  • 空行は読み飛ばしたい

このような場合、SplFileObjectのインスタンスに対して以下のようにフラグ設定する。

改行コードは取り除きたいが空行は空行のままで残したい場合はDROP_NEW_LINEのみ設定し、READ_AHEADはあってもなくてもよい。ただし最後の行の次に空行が付いてきてしまう。

テスト用ファイル

以下のテキストファイルで確認した。エンコーディングはUTF-8で最後の行や空行も含めて各行末のコードはLF

テスト用コード

  • コントローラーでファイルを読み込み、行単位で配列に格納
  • dd()で配列の内容を確認(returnは実行されない)
  • setFlags()の引数を変化させて結果を比較

結果

フラグ設定なしの場合

setFlags()の行をコメントアウトし、フラグ設定なしで実行した場合。

  • 改行コードが残る
  • 最終行の後に空文字列("")が付いてくる

SKIP_EMPTYのみを設定した場合

  • 改行コードが残る
  • 最終行の後にbooleanfalseが付いてくる

DROP_NEW_LINEのみを設定した場合

  • 改行コードは取り除かれる
  • 改行のみの空行は空文字列になる
  • 最終行の後に空文字列が付いてくる

SKIP_EMPTY | DROP_NEW_LINE

  • 改行コードは取り除かれる
  • 空行は取り除かれる
  • 最終行の後にbooleanfalseが付いてくる

READ_AHEAD | SKIP_EMPTY

  • 改行コードは残る
  • 空行は残る
  • 最終行の後には何も付かない

READ_AHEAD | DROP_NEW_LINE

  • 改行コードは取り除かれる
  • 改行のみの空行は空文字列になる
  • 最終行の後に空文字列が付けられる

READ_AHEAD | SKIP_EMPTY | DROP_NEW_LINE

  • 改行コードは取り除かれる
  • 改行のみの空行は取り除かれる
  • 最終行の後には何も付かない

CSVファイル読み込み時

概要

以下のようにCSVファイルを読み込みたい場合。

  • 空行はスキップしたい
  • フィールド中の改行は取り除きたい

このような場合、SplFileObjectのインスタンスに対して以下のようにフラグ設定する。

空行はスキップするがフィールド中の改行は残したい場合、フラグの設定だけでそのような結果を得ることはできないようである。

READ_CSVのみ設定し、内容がnullのデータを登録せずに飛ばしていくことになる。

テスト用ファイル

テスト用コード

結果

READ_CSVのみの場合

  • 空行に対応してnullの要素が残る
  • フィールド中の改行は残る
  • 最終データの後にnullの要素が付く

SKIP_EMPTYを追加

  • 空行に対応してnullの要素が残る
  • フィールド中の改行は残る
  • 最終データの後にfalseの要素が付く

DROP_NEW_LINEを追加

  • 空行に対応してnullの要素が残る
  • フィールド中の改行は取り除かれる
  • 最終データの後にnullの要素が付く

SKIP_EMPTY | DROP_NEW_LINEを追加

  • 空行は取り除かれる
  • フィールド中の改行は取り除かれる
  • 最終データの後にfalseの要素が付く

READ_AHEAD | SKIP_EMPTYを追加

  • 空行に対応してnullの要素が残る
  • フィールド中の改行は残る
  • 最終データの後には何も付かない

READ_AHEAD | DROP_NEW_LINEを追加

  • 空行に対応してnullの要素が残る
  • フィールド中の改行は取り除かれる
  • 最終データの後にnullの要素が付く

READ_AHEAD | SKIP_EMPTY | DROP_NEW_LINEを追加

  • 空行は取り除かれる
  • フィールド中の改行は取り除かれる
  • 最終データの後には何も付かない

 

 

PHP – CSV – 書き出し – SplFileObject

概要

SplFileObjectによるCSVファイルへの書き出しについて整理する。

  • ファイル名を指定してSplFileObjectのインスタンスを生成
    • $file = new \SplFileObject('CSVファイルパス', 'a'); 
    • $open_mode='a'(書き出し・追記)を設定
  • アクションの引数で指定したRequestオブジェクトからフォームパラメーターを読み込み、CSV書込み用の配列変数にセット
    • $request->input('INPUT要素名');
  • 配列の内容をファイルへ書き出し
    • $file.fputcsv(1行分の配列変数);
    • 必要に応じて引数で区切り・囲み・エスケープ記号を指定
  • ファイルをクローズ
    • $file = null;
  • 更新後のデータで表示するようリダイレクト

基本例

例として以下のようなアプリケーションを考える。CSVファイルの読み込み手順は”CSV – 読み込み“の内容と同じ。

  • GETリクエストに応じて
    • 入力フォームを表示する
    • フォームの下にCSVファイルの内容を表示する
  • フォームに入力し送信ボタンを押してPOSTリクエスト
    • 入力された内容をCSVファイルに追加書き出し
    • 更新後のデータを表示するためリダイレクト

ルーティング

以下の様にルーティングする。

コントローラー~GET・表示処理

CSV – 読み込み“と同じ手順でCSVファイルを読み込み、ビューに引き継ぐ。

  • SplFileObjectインスタンスの生成
    • storage/appディレクトリーに配置したCSVファイルを指定
    • storage_path()関数を利用してパスを取得
  • CSV読み込みのためのフラグセット
  • 行単位で読み込み配列に格納
  • データをビューに引き継いでレンダリング

ビュー

表示

この例でのビューの表示内容は以下の2つ

  • CSVファイルに追加するデータのフォーム
  • コントローラーから引き継いだCSV読み込みデータの内容を表示

ビューのうちbody要素内のBladeコードは以下のとおり。form要素内の冒頭に@csrfでCSRF対策を指定している。

CSVにデータが2行だけ登録されている状態の、ブラウザーの表示例は以下のとおり。

フォーム入力・POST

上記のフォームに追加するデータを入力し、保存ボタンで登録のためのPOSTリクエスト。

コントローラー~POST・登録処理

ビューのフォームからPOSTされたパラメーターを、CSVファイルに追加する。

コード

POSTパラメーターの取得・変数セット

  • アクションの引数でRequestオブジェクトを受け取り、input()メソッドで各パラメーターを取得
  • 取得したパラメーターを行データの配列にセット

行データのCSVファイルへの追加

  • fputcsv()メソッドで行データをCSVファイルに追加
  • 追加後にSplFileObjectの変数にnullを代入し、ファイルクローズ相当の処理をしている

リダイレクト

保存されたCSVデータが反映された状態で再表示するため、リダイレクトを指示している。

return redirect('ルーティング先');

  • view()によるレンダリングはビューファイルを指定して再表示
  • redirect()によるリダイレクトはルーティング設定のURIを指定してコントローラーから実行

再表示結果

CSVファイルに追加されたデータが反映されている。

PHP – CSV – 読み込み – SplFileObject

概要

SplFileObjectによるCSVファイルの読み込みについて整理する。手順概略は以下のとおり。

  • ファイル名を指定してSplFileObjectのインスタンスを生成
    • $file = new \SplFileObject('csvファイルパス');
    • $open_modeはデフォルト値の'r'(読み込み)
  • CSV読み込みのためのフラグをセット
    • $file.setFlags(...);
  • ファイルを読み込み
    • foreachで行単位データを取得
    • 行データは各フィールド値を要素とする配列

なお、Splは”Standard PHP Library”の略。

基本例~一括読み込み

例として、GETリクエストに応じて所定の場所に配置されたCSVファイルを読みだし、行データを要素とする配列に格納し、その内容をブラウザーに表示するアプリケーションを考える。

CSVファイルの配置

storage/app/ディレクトリーにCSVファイルを配置した場合は、storage_path()関数にstorageディレクトリーを基準としたパスを指定してフルパスを得ることができる。

たとえば以下の内容のファイルをstorage/app/csv_sample_utf8.csvとして配置する(エンコーディングはUTF-8)。3つのカラムがカンマ','で区切られている。

ルーティング

以下の様にルーティング設定する。

コントローラー~処理本体

コード

コントローラーのアクションは以下のとおり。

SplFileObjectインスタンスの生成

PHPのSplFileObjectのインスタンスを、CSVファイルのパスを指定して生成する。

  • LaravelでPHPのクラスを使う場合は、クラス名の冒頭に'\'を記述
  • storage_path()関数によりアプリケーションのstorageディレクトリーを基準にしたCSVファイルのパスを指定

フラグの設定

SplFileObjectクラスのsetFlags()メソッドで、必要なフラグを'|'(or)で連ねて設定する。CSV読み込み時のフラグの影響についてはこちらを参照。

ファイルの読み込み

ファイルの各行をforeachで取り出し、配列に格納していく。

各行はREAD_CSVフラグによりCSVとみなされ、3つのフィールドが分解されて要素数3の配列になる。この結果、$linesには6行分のCSVから読み込んだ配列が格納され、各配列は3つのフィールドに対応する要素を持つ。

ファイルクローズ

ファイルクローズのコマンドはないが、インスタンスの参照変数にnullを代入してインスタンスを破棄している。

PHPマニュアル(SplFileObject)のUser Contributed Notes (64)でSplFileObjectのインスタンスにnullをセットする意義が示されている。

ビューへの引継ぎ

タイトルとCSVから読み込んだ配列をビューに渡している。

ビューにおける表示

ビューでは、コントローラーから受け取った変数をHTMLとして展開している。

以下はブラウザーでの表示例。

ファイルの順次読込

CSVファイルのサイズがかなり大きい可能性がある場合、一括して配列に読み込むとサーバーのメモリーを過大に圧迫することが考えられる。

CSVの内容をデータベースに登録するような処理の場合、1行ずつ読み込んで処理し、サーバーの負荷を軽減することを検討すべき。

エンコーディング

読み込むCSVファイルのエンコーディングがUTF-8以外の場合、そのまま読み込んだだけでは適正に扱えない。このようなことは表計算ソフトで作成したファイルがShift-JISというのはよくある。

SplFileObjectでCSVファイルを読み込む場合、1行のデータが各フィールドに対応した要素を持つ配列となるので、mb_covert_variablesを使う。

 

Laravel – dump()とdd()

概要

PHPのvar_dump()と同じような変数表示機能を提供する。

dump()

dump()は変数の内容をブラウザー上に表示する。

たとえばコントローラー内で以下の記述があるとき

ビューの内容に先立って、dump()による変数の内容が表示される。配列などの場合、個別にその内容を展開・折りたたみできる。

dd()

dump()の場合、エラーが生じてビューにエラーメッセージが表示されるとdump()の結果が表示されない。

dd()を使うと、その時点でブラウザーにdump()と同じ内容を表示し、実行が停止する(dump and die)。

 

Laravel – ルートパラメーターのwhereによる検証

概要

ルートパラメーターがURIに含まれて送られてきた時、ルーティングの段階で、正規表現を使って検証することができる。

検証の結果正規表現にマッチすれば処理され、マッチしなければ”404 Not Found”エラーとなる。

ルーティングの書き方

以下の様に、通常のルーティングのget()メソッドにwhere()を適用する。

たとえば以下は、ルートパラメーターが2桁の整数(00や01などを含む)であることを検証している。数字2桁ならValidと表示され、数値の桁が違ったり、数字以外の文字が含まれている場合は404エラーとなる。

リクエスト先がコントローラー・アクションでもこれは使える。以下の例ではリクエストパラメーターが数字2桁の場合だけアクションが実行され、そうでなければ404エラーとなる。

 

Laravel – POSTリクエストパラメーター

概要

Laravelでは、フォームからPOSTされたリクエストパラメーターもクエリーパラメーターと同じようにRequestオブジェクトを介して取得できる。

  • formからのメソッド(POST)にしたがって、actionで指定した送信先に、リクエストパラメーターがHTTPリクエストのボディーに含められて送信される
  • actionの送信先からコントローラーのアクションにルーティング
  • アクションでパラメーターを取得して利用

フォーム

例として、以下のフォームを含むビューでリクエストを受け付ける。

  • 入力項目=パラメーターはuser_namepost
  • メソッドはPOST
  • actionのターゲット取得にurl()ビューヘルパーを使っている
  • form開始タグの直後に@csrfディレクティブがあるが、これはCSRF(Cross Script Request Forgery)を防止するためのトークンを埋め込むためのもので、デフォルトではこれがないとフォーム送信時に”419 Page Expired”エラーになる

ルーティング

フォームからの送信が送られるactionのターゲットをコントローラーのアクションにルーティングする。この時はパラメーターについて特に関与しない。

以下は上記の例のルーティング例。

コントローラー

ルーティングされたコントローラーのアクションで、リクエストパラメーターを取得して利用する。

必須事項

クエリーパラメーターのコントローラーにおける必須事項を参照。

アクションにおけるパラメーターの取得

Requestオブジェクトのinput()メソッド

アクションの引数で指定したRequestオブジェクトのinput()メソッドで引数にパラメーター名を指定すると、これに対応したパラメーターの値が得られる。

$request->input('パラメーター名');

  • $requestはアクションの引数名で任意
  • パラメーター名はフォーム各要素のname属性で指定した名前

冒頭の例に対応したコントローラーの記述例は以下のとおり。

ビューはこれらの値を使って表示される。

request()関数

Requestオブジェクトのinput()メソッドではなく、request()関数の引数にパラメーター名を指定してもパラメーターの値を取得できる。

request('パラメーター名');

先の例のアクションの部分をこれで書き換えると以下の様になる。