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

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

Laravel開発、所有情報がある書籍を削除できないようにする

所有している書籍がある状態で、書籍情報自体を削除してしまうと、存在しない本を所有している状態となってしまいます。

動作検証の中でこういった現象がおこることがわかったので、対処していきます

今回の目的

本を所有しているユーザーがいる場合、書籍情報を削除できないようにする

なぜやるか

関連情報を必要とするユーザーの情報が削除されることを防ぐため

やりたいこと

  • 制約を設けて関連情報が削除できないようにする
  • 削除できない状態であることをユーザーに通知する

やったこと

  • 外部キー制約を追加する
  • 削除できないことを確認する
  • エラー画面表示を回避し、削除不可通知を出す

実施内容

所有者がいる書籍情報が削除できてしまう

テストを書くことと平行して実際にあらゆる動作を自分で実施していたところ、この問題に気づきました。

所有書籍を登録した状態で書籍自体を削除すると…普通にすべて消えました、所有書籍情報は残っていますが、書籍自体が削除されたので結果としては何も表示されない状態となったのです。

DBを見ると、書籍情報としてはしっかり残っています。

 

所有者がいる以上、書籍情報は必要です。そこで、所有者がいる場合は書籍情報を削除できないように変更することにしました。

 

データに制約を設ける

外部キーを設定する

まず、データを削除できないように変更しました。

マイグレーションファイルで、所有書籍情報Propertyテーブルにて書籍情報を参照しているbookdata_idについて外部キーを設定します。

 

 # ~/database/migrations/xxxx_create_properties_table.php

public function up()
{
Schema::create('properties', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->integer('bookdata_id')->unsigned();
$table->integer('number');
$table->date('getdate')->nullable();
$table->text('freememo')->nullable();
$table->timestamps();

$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('bookdata_id')
->references('id')->on('bookdata');
});
}

bookdata_idに外部キー制約を付与しました。

 

これで外部キー制約が付与され、所有書籍として利用している本の情報は消せなくなりました。

f:id:Fippiy:20190502124706p:plain

削除エラー

削除しようとしたところエラーとなりました。

意図した動きではあるのですが、エラーメッセージがそのまま表示されるのは好ましくありません。

 

エラー表示画面がでないように対処する

このままでは削除不可データを削除する度にエラー画面が表示されてしまうため、エラー画面ではなく、削除出来ない旨のメッセージが表示される方がいいでしょう。

バリデーションによってエラー文を返してビューに表示させることにしました。

 

削除アクションにバリデーションを追加していきます。

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

public function destroy($id)
{
// 画像保存ディレクトリ設定
$save_directory = "book_images";
// 削除レコード取得
$delete_book = Bookdata::find($id);

// 写真削除がある場合
if (isset($delete_book['picture'])) {

書籍削除の冒頭部分です、画像フォルダ設定と削除レコードを取得して画像が登録されている場合は画像削除を先に実施する…といった流れになっています。

 

この先頭部分に所有者がいないかどうかチェックすることにしました。

所有者がいれば、削除できないという処理を始めに追加するわけです。

public function destroy($id)
{
$have_property = Property::where('bookdata_id', $id)->first();
if (count($have_property) > 0) {
$have_book = false;
} else {
$have_book = true;
}
$validator = Validator::make(['bookdata_id' => $have_book],
 ['bookdata_id' => 'accepted'], ['所有者がいるため削除できません']);
if ($validator->fails()) {
return redirect('book/'.$id)
->withErrors($validator)
->withInput();
}
// 画像保存ディレクトリ設定
$save_directory = "book_images";

削除idを元に所有者情報の入っているPropertyテーブル内のbookdata_idを検索して取得しています。1件でもあれば所有者がいるので、全件検索は不要です。

その後、バリデーターでaccepted判定を行うので、情報のありなしでtrue等を設定することにしました。

そして、所有者がいる場合はリダイレクトさせてエラーメッセージを返します。

# 削除不可メッセージ

f:id:Fippiy:20190502133214p:plain

所有者がいるため削除不可

削除実施前にバリデーターによるチェックを行い、問題がある場合はエラーメッセージを返し、問題なければ通常の削除処理を行うことで、エラー画面出力を回避しました。

 

書籍情報の削除可否についてはこれで対処できました。