Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

Laravel開発、入力フォームを編集してカンマ区切りテキストからISBNを一括で登録できるようにする

複数のISBNコードを登録することはできましたが、フォーム内にinputタグを10件追加するという形で複数対応していました。

せっかくここまで実施できたので、inputフォームに個別に入力することから、テキストボックスに複数の値を入力できるようにして一括登録もできるようにしました。

今回の目的

ISBNをまとめて登録できるフォームを作成し、一括登録できるようにする

なぜやるか

複数登録フォームではinputタグ毎に値を入力する手間が発生するため、テキスト化したデータをコピーすることで一括登録できるようにするため

やりたいこと

  • 一括登録フォームを用意して、一度にまとめて登録処理ができるようにする

やったこと

  • 一括登録フォームを作成する
  • 複数登録と一括登録で同じアクションを利用する
  • 登録されたデータをカンマで区切って分割する
  • 分割処理に改行コードにも対応させる
  • ISBNにハイフンが含まれる場合は除外できるようにする
  • 数値以外の情報は受付しないようにする
  • 登録上限を設定する

実施内容

一括登録データを受け取れるようにする

フォームを変更する

まずは、カンマ区切りを受け付けるテキストフォームを作成しました。

前回同様に作成済みのフォームはそのまま残置し、新しく一括登録用のビューを作成しました。

f:id:Fippiy:20190519100357p:plain

入力フォーム(テキストエリア)

 # ~/resources/views/book/isbn_some_input.blade.php

<form action="/book/isbn_some" method="post">
 {{ csrf_field() }}
 <div class="form-contents">
  <div class="form-input form-one-size">
   <div class="form-label">ISBNコード</div>
   <div>
    <textarea class="form-input__detail" type="numbers" name="isbns"></textarea>
   </div>
  </div>
 </div>
 <div class="form-foot">
  <input class="send isbn" type="submit" value="登録">
 </div>
</form>

複数登録フォームではinputタグを10件並べていましたが、textareaとして入力フォームを作成しました。

 

しかし、このままでは"isbns"という名前に対して入力値が全部セットされてしまいますので、カンマで区切って分割したいのです。

 

カンマ区切りで追加する 

コントローラーで受け取ったデータを分割します。こちらの処理については、複数登録のアクションを流用し、差分となる箇所にifを利用してどちらにも対応できるようにする形で作成しました。

 

作成するにあたっては、以下のサイトを参考にさせて頂きました、ありがとうございます。 

www.php-mysql-linux.com

www.php.net

上記を参考にフォームより受け取ったデータを分割してみました。

 

textareaタグのisnbsのみ分割するので、キーの名前でif文で処理して分割することにしました。

配列キー確認

www.php.net

これで受け取った値によって処理できそうです。

  

コントローラを修正

# ~/app/Http/Controllers/BookController.php

public function postIsbnSome(Request $request){
 // フォームデータ取得
 unset($request['_token']); // トークン削除
 $isbns = $request->all(); // isbnコードをフォームから取得
 if(array_key_exists('isbns', $isbns)){
  $data = $isbns['isbns'];
  $isbns=explode(',',$data);
 }
 $count = count($isbns); // 取得件数
 $isbnrecords = ; // データ格納用配列

isbnsという名前のキーがあれば追加の処理を実施します。

一度$dataという変数で受け取ってからexplode(',',$data)としてカンマで分割したデータを$isbnsに戻しています。

ifで分岐させているので、既存の複数ISBNインプットフォームにも対応した状態です。

 

# terminal

$isbns

=> [

     "11111111111111",

     "222222222222",

   ]

","で区切られた情報として$isbnsに格納できました。

  

データ分割ができたので、残りの処理を行うための配列に追加してやればよさそうです。

# ~/app/Http/Controllers/BookController.php

// 処理用配列へ追加
for ($i = 0; $i < $count; $i++){
 if ($isbns[$i] != null){
  $isbnrecords = array(
   'process' => 'processing',
   'number' => $i+1,
   'isbn' => $isbns[$i],
   'msg' => null,
  );
 }
}

直後の$isbnrecords配列に処理状況ステータスを加えている所です。

前回は'isbn*'というフォーム受け取った配列のキー名でISBNを設定していました。

今回の配列にはキーがないので要素毎に取り出しすることでキー名にたよらずに全ての値が処理できるようにしました。

※しかし、これでは複数ISBNコードでは動かないことが後で分かりました。気づいてから修正しましたので、詳細は後述します。

 

処理用の配列にさえいれてしまえば、後の処理は同じです。

 

 

動作確認する

まずは動かす

今までの内容で問題なく動作することを確認していきます。

f:id:Fippiy:20190519101043p:plain

カンマ区切りで入力

13桁コードをテキストでサンプル用意していたので、カンマをつけて貼付し登録。

 

f:id:Fippiy:20190519101208p:plain

カンマ付き結果

2件目以降が13桁ではありませんとメッセージ出力されました。

早速失敗してます…。

 

受け取った値を詳しくみてみました。 

# terminal

$isbnrecords

=> [

     [

       "process" => "processing",

       "number" => 1,

       "isbn" => "9784797398892",

       "msg" => null,

     ],

     [

       "process" => "processing",

       "number" => 2,

       "isbn" => """

         \r\n

         9784756918765

         """,

       "msg" => null,

     ],

2件目以降に改行が入っていました。

確かに貼付したデータも改行しています。こちらが考慮されていなかったようです。

 

データを修正して動作させる

改行コードを削除し、ISBNコード+カンマのみのデータで再確認します。

f:id:Fippiy:20190519101633p:plain

カンマ区切り入力2

当初のコードに対応するべきデータはこの状態でした。 

f:id:Fippiy:20190519101859p:plain

カンマ付き結果2

改行をなくしたことで、正常に登録処理できました。

 

処理データも確認しておきます。

# terminal

$isbnrecords

=> [

     [

       "process" => "processing",

       "number" => 1,

       "isbn" => "9784797398892",

       "msg" => null,

     ],

     [

       "process" => "processing",

       "number" => 2,

       "isbn" => "9784756918765",

       "msg" => null,

     ],

想定通りの値が取得できていました。

 

改行を考慮した処理に修正する

カンマ区切りによるデータ分割対応はできました。

しかし、改行も考慮させたフォームとしておきたいところです。

実際、初めに実施したように改行してあるデータを扱うこともありますし、カンマなしの改行のみで複数データを扱うことも多いでしょう。

パターンをあげるときりがないので、改行とカンマが考慮されていれば良しとして進めます。

 

手順としては、正規表現による複数の区切りパターンを設定することにしました。こちらを参考にさせて頂きました、ありがとうございます。

php.net

 

カンマと空白文字で分割という例が上記サイトにありましたので、今のパターンにそのまま合うので適用しました。

# ~/app/Http/Controllers/BookController.php

// フォームデータ取得
unset($request['_token']); // トークン削除
$isbns = $request->all(); // isbnコードをフォームから取得
if(array_key_exists('isbns', $isbns)){
 $data = $isbns['isbns'];
 // $isbns=explode(',',$data);
 $isbns = preg_split("/[\s,]+/", $data);
}
$count = count($isbns); // 取得件数
$isbnrecords = ; // データ格納用配列

カンマだけでなく空白文字についても分割の対象として追加しました。

 

この状態で再度動作確認します。

f:id:Fippiy:20190519101043p:plain

カンマ区切り+改行あり

初めに動作確認した、カンマと改行があるパターンで登録を実施。

 

f:id:Fippiy:20190519101859p:plain

複数登録結果

問題なく全て登録できました。

 

空白文字にも対応しているので、あわせて確認します。

f:id:Fippiy:20190519105635p:plain

改行のみ

カンマを削除し改行したリストで登録します。

f:id:Fippiy:20190519105617p:plain

複数登録結果

正常に処理できました。
 

以上で、textareaタグでまとめてデータを受け取り一括登録することができるようになりました。

 

文字情報を判定する

更に考慮すべき情報に対応する

テキストエリア化することでまとめて登録することには対応できました。

しかし、他に考慮する点がまだあるので対応していきます。

ここで実施することは

  • 特定の文字を予め削除する
  • 数値以外のデータは対象外とする 

この2点です。

 

特定の文字を削除する

特定の文字を削除すると突然でてきましたが、経緯は次のとおりです。

元々API情報を参考にするためにamazonの本検索でいくつかピックアップしていました。検索すれば簡単に情報が出てきます。

そこで、ISBNコードを確認すると…。

f:id:Fippiy:20190519111144p:plain

本情報サイト抜粋

ISBNコードが記載されています。今回のAPIは13桁に対応していました。

13桁コードには"-"が付与されています。

今まで毎回削除して動作確認していましたが、自動的にハイフンを削除できるようにしておくことにしました。

 

特定文字削除の方法については、こちらを参考にさせて頂きました、ありがとうございます。

qiita.com

フォームより受け取ったデータに対してハイフンを取り除く設定を追加することで、ユーザーが削除する手間を省きます。

 # ~/app/Http/Controllers/BookController.php

// 処理用配列へ追加
for ($i = 0; $i < $count; $i++){
 if ($isbns[$i] != null){
  // isbn設定
  $setisbn = str_replace('-', '', $isbns[$i]); // ハイフンを含んでいる場合は取り除く
  // 配列格納
  $isbnrecords = array(
   'process' => 'processing',
   'number' => $i+1,
   'isbn' => $setisbn,
   'msg' => null,
  );
 }
}

ISBN要素作成時に"-"を削除するように設定を追加しました。

 

こうすることで、ハイフンのついたテキストであってもそのまま貼付して登録できるようになります。

f:id:Fippiy:20190519111254p:plain

ISBN登録

この状態でも登録可能になりました。 

 

数値のみ受付できるようにする

テキストエリアでは入力できる文字全てが扱えます。

しかし、取得するISBNは数値の13桁と決まっていますので、これに対応していない場合は処理できないようにします。

元々inputフォームの時はどうしていたか…というと、inputフォームのタイプをnumberとしていました。数値のみ入力できる状態としていたのです。

しかし、この方法は今回は使えません。

 

そこで、ハイフンを取り除く作業は先程完了しているので、次のフォームデータ判定にて、取得したISBNが数値であるかどうかを判定することにしました。

 

数値判定はこちらを参考にさせて頂きました、ありがとうございます。

www.php.net

 

フォームデータ評価のパターンとして数値判定を追加します。 

# ~/app/Http/Controllers/BookController.php

// フォームデータ評価
for ($i = 0; $i < $count; $i++){
 if ($isbnrecords[$i]['process'] == 'processing'){ // 処理変数が処理中の場合は処理を実施する
  if (ctype_digit($isbnrecords[$i]['isbn']) == false) {
   data_set($isbnrecords[$i], 'msg', '数値ではありません'); // 数値でない場合はメッセージ格納
   data_set($isbnrecords[$i], 'process', 'error'); // 処理ステータスエラー
  } elseif (mb_strlen($isbnrecords[$i]['isbn']) != 13){
   data_set($isbnrecords[$i], 'msg', '桁数が13桁ではありません。');
   // 13桁でない場合はメッセージ格納
   data_set($isbnrecords[$i], 'process', 'error'); // 処理ステータスエラー

受け取った値に対して初めに数値であることを判定しています。ここで数値でなければメッセージを付与し処理エラーとしています。

 

動作確認をします。

f:id:Fippiy:20190519113520p:plain

入力パターン検証

パターンをいろいろ入力してためしてみました。

  1. 数値
  2. ハイフン付き数値
  3. 全角
  4. @がついている
  5. で区切られている
  6. "w"が入っている

f:id:Fippiy:20190519113538p:plain

検証結果

上2つは正常に処理されていますが、残りは全て数値でないという扱いではじかれています。 

 

ISBN複数登録フォームを修正する 

既存フォームから登録が失敗する

本記事の途中でも触れましたが、既存のISBN複数登録フォームからの登録ができなくなっていました。

今回のコントローラー処理は、複数登録と一括登録で同じアクションを利用していますので、どちらにも対応できる状態…としていたつもりでした。

 

改めて内容を確認します。

f:id:Fippiy:20190517152743p:plain

複数ISBN入力フォーム

複数ISBN入力フォームから登録しようとするとエラー発生。

# ビュー画面エラー表示

  1. // isbnsキーが設定されている場合は指定キーで区切る
  2. if(array_key_exists('isbns', $isbns)){
  3. $data = $isbns['isbns'];
  4. $isbns = preg_split("/[\s,]+/", $data); // カンマと空文字列で区切る
  5. }
  6. $count = count($isbns); // 取得件数
  7. $isbnrecords = ; // データ格納用配列
  8. // eval(\Psy\sh());
  9. // 処理用配列へ追加
  10. for ($i = 0; $i < $count; $i++){
  11. if ($isbns[$i] != null){
  12. // isbn設定
  13. $setisbn = str_replace('-', '', $isbns[$i]); // ハイフンを含んでいる場合は取り除く
  14. // 配列格納
  15. $isbnrecords = array(
  16. 'process' => 'processing',
  17. 'number' => $i+1,
  18. 'isbn' => $setisbn,
  19. 'msg' => null,
  20. );
  21. }
  22. }

$isbn[$i]でデータが選択できていないようです。

 

配列の取得方法に問題がある

一括登録作成時に、配列を番号指定で順番に取り出す記述に変更していました。ところが連想配列で番号指定はできないようです。

 

複数ISBN登録時のコード

// 処理用配列へ追加
for ($i = 0; $i < $count; $i++){
 if ($isbns['isbn'.$i] != null){
  $isbnrecords = array(
   'number' => $i+1,
   'isbn' => $isbns['isbn'.$i],
   'msg' => null,
  );
 }
}
$count = count($isbnrecords);

$isbnsには["isbn0",1234567890123,"isbn1",2345678901234]といった配列が入っており、キー名によってISBN番号を取り出していました。

 

現在のコード

// 処理用配列へ追加
for ($i = 0; $i < $count; $i++){
 if ($isbns[$i] != null){
  // isbn設定
  $setisbn = str_replace('-', '', $isbns[$i]); // ハイフンを含んでいる場合は取り除く
  // 配列格納
  $isbnrecords = array(
   'process' => 'processing',
   'number' => $i+1,
   'isbn' => $setisbn,
   'msg' => null,
  );
 }
}

 同じことを実施していたつもりですが、キー名のある配列に対して$isbns[0]、$isbns[1]としても値がとりだせていませんでした。

 

両方に対応させる

バリューの取得手順を見直す事にしました。

# ~/app/Http/Controllers/BookController.php

// 処理用配列へ追加
$i = 1;
foreach($isbns as $isbn){
 if ($isbn != null){
  // isbn設定
  $setisbn = str_replace('-', '', $isbn); // ハイフンを含んでいる場合は取り除く
  // 配列格納
  $isbnrecords = array(
   'process' => 'processing',
   'number' => $i,
   'isbn' => $setisbn,
   'msg' => null,
  );
 }
 $i++;
}

foreachによるバリュー取り出しに変更しました。

今回の処理ではキー名は結果的に不要となるので(ISBN番号さえ取得出来ればいい)、値だけ取り出しができれば問題ありません。こうすることでどちらの配列にも対応した処理内容となりました。

 

登録上限を設定する

これで一括登録対応は完了しました。

いまのままでは特に上限なくまとめて登録できる状態なのですが、大量投入に対しての対応を特に何もおこなっていません。

対応できればいいのですが、一端登録上限数をもうけておくことで対応することにしました。

# ~/app/Http/Controllers/BookController.php

// 処理用配列へ追加
$i = 1;
foreach($isbns as $isbn){
 if ($isbn != null){
  if ($i > 20){ // 一度に登録できる上限
   break;
  }
  // isbn設定
  $setisbn = str_replace('-', '', $isbn); // ハイフンを含んでいる場合は取り除く
  // 配列格納
  $isbnrecords[] = array(
   'process' => 'processing',
   'number' => $i,
   'isbn' => $setisbn,
   'msg' => null,
  );
 }
 $i++;
}

件数条件を追加しました、大量のデータが送信されたとしてもこれによって制限をかけることができます。