41
47

More than 3 years have passed since last update.

Laravel CRUD

Last updated at Posted at 2020-08-23

はじめに

LaravelでCRUDを作っていきます。

やらないこと

  • 認証関係は扱いません。
  • 削除の前の確認などJavaScriptで実現される機能は今回は作りません。

つくるもの

アクション 画面の有無 内容
index 画面あり 一覧表示画面
create 画面あり 新規入力フォーム
store 画面なし 追加処理(createの登録ボタン)
show 画面あり 詳細表示
edit 画面あり 変更フォーム(既存の値が入っている状態)
update 画面なし 変更処理(editの更新ボタン)
destroy 画面なし 削除処理(showの削除ボタン)
流れ
index(一覧表示) ┳ create(新規作成画面) ━ store(新規保存)
            ┗ show(詳細表示)     ┳ edit(編集画面) ━ update(上書き保存)
                        ┗ destroy(削除)     

準備

テーブルの作成

作成するテーブル

id name telephone email created_at updated_at
ID 名前 電話番号 メールアドレス 作成日時 更新日時

modelファイルとmigrationファイルの作成

terminal
php artisan make:model Models/Member -m

-mオプションでマイグレーションファイルも一緒に作成します。

下記の2つのファイルが作成されます。
app\Models\Member.php
database\migrations\xxxx_xx_xx_xxxxxx_create_members_table.php

migrationファイルの編集

database\migrations\xxxx_xx_xx_xxxxxx_create_members_table.php
public function up()
  {
    Schema::create('members', function (Blueprint $table) {
      $table->id();
      $table->string('name',20);
      $table->string('telephone',13)->nullable()->unique();
      $table->string('email',255)->nullable()->unique();
      $table->timestamps();
    });
  }

public function down()
  {
    Schema::dropIfExists('members');
  }

migrationの実行

terminal
php artisan migrate

membersテーブルが作成されます。

レコードの挿入

表示確認用にmembersテーブルにレコードを入れます。

seederファイルの作成

terminal
php artisan make:seeder MembersTableSeeder

database\seeds\MembersTableSeeder.phpが作成されます。

seederファイルの編集

database\seeds\MembersTableSeeder.php
    public function run()
     {
         DB::table('members')->insert(
             [
               [
                 'name'=>'山田',
                 'telephone'=>'xxxx-xxxxx',
                 'email'=>'yamada@example.com',
                 'created_at'=>now(),
                 'updated_at'=>now(),
               ],

               ]
         );
     }

DatabaseSeederへの登録

作成したMembersTableSeederをDatabaseSeederに登録します。

database\seeds\DatabaseSeeder.php
public function run()
  {
    $this->call(MembersTableSeeder::class);
  }

seederファイルの実行

terminal
php artisan db:seed

membersテーブルにレコードが入ります。

controllerの作成

terminal
php artisan make:controller MemberController --resource

--resourceオプションをつけると、7つのアクションの雛形が予め用意されます。

controllerの編集

7つのアクションの雛形が予め用意されています。

app\Http\Controllers\MemberController.php
//追加
use Illuminate\Support\Facades\DB;
use App\Models\Member;

public function index()
  {
    //
  }

public function create()
   {
     //
   }

public function store(Request $request)
  {
    //
  }

public function show($id)
  {
    //
  }

public function edit($id)
  {
    //
  }

public function update(Request $request, $id)
  {
    //
  }

public function destroy($id)
  {
    //
  }

一覧画面(index)

routingの追加

/member/indexにアクセスした場合のルーティングを追加します。

route/web.php
//追記
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
});

controllerの編集

membersテーブルからデータを取ってきて、viewに渡します。

app\Http\Controllers\MemberController.php
public function index()
  {
    //memberテーブルからname,telephone,emailを$membersに格納
    $members=DB::table('members')
      ->select('id', 'name', 'telephone', 'email')
      ->get();

    //viewを返す(compactでviewに$membersを渡す)
    return view('member/index', compact('members'));
  }

viewの新規作成

resources\views\member\index.blade.php
<h1>一覧表示</h1>

<table>
<tr>
<th>ID</th>
<th>名前</th>
<th>電話番号</th>
<th>メールアドレス</th>
</tr>
@foreach($members as $member)
<tr>
<td>{{$member->id}}</td>
<td>{{$member->name}}</td>
<td>{{$member->telephone}}</td>
<td>{{$member->email}}</td>
</tr>
@endforeach
</table>

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/index にアクセスし、一覧表示ができていることを確認します。
Ctrl+Cで簡易サーバーを終了します。

新規登録(create)

routingの追加

/member/createにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');

  //追記
  Route::get('create', 'MemberController@create')->name('member.create');
});

controllerの編集

create.blade.phpを返します。

app\Http\Controllers\MemberController.php
public function create()
  {
    return view('member/create');
  }

viewの新規作成

新規作成画面を作ります。
名前だけ入力必須にしています。

resources\views\member\create.blade.php
<h1>新規作成</h1>

<form method="POST" action="">
  @csrf

  <div>
    <label for="form-name">名前</label>
    <input type="text" name="name" id="form-name" required>
  </div>

  <div>
    <label for="form-tel">電話番号</label>
    <input type="tel" name="telephone" id="form-tel">
  </div>

  <div>
    <label for="form-email">メールアドレス</label>
    <input type="email" name="email" id="form-email">
  </div>

  <button type="submit">登録</button>

</form>

導線(index→create)

一覧表示画面から新規作成画面へのリンクです。

resources\views\member\index.blade.php
<a href="{{ route('member.create') }}">{{ __('新規作成') }}</a>

導線(create→index)

新規作成画面から一覧表示画面へのリンクです。

resources\views\member\create.blade.php
//追加
<a href="{{ route('member.index') }}">{{ __('一覧へ戻る') }}</a>

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/create にアクセスし、新規入力画面ができていることを確認します。
(この時点では、登録ボタンを押してもエラーになります。)
Ctrl+Cで簡易サーバーを終了します。

新規保存(store)

新規追加画面で入力した値をDBに保存します。

routingの追加

/member/storeにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');

  //追加
  Route::post('store', 'MemberController@store')->name('member.store');
});

controllerの編集

フォームで入力された値をmembersテーブルに格納します。

app\Http\Controllers\MemberController.php
public function store(Request $request)
  {
    $member=new Member;

    $member->name=$request->input('name');
    $member->telephone=$request->input('telephone');
    $member->email=$request->input('email');

    $member->save();

    //一覧表示画面にリダイレクト
    return redirect('member/index');
  }

viewの新規作成

なし

導線(create→store)

新規作成画面から新規保存へのリンクです。

resources\views\membercreate.blade.php
//<form method="POST" action="">
//↓フォームの送信先の変更
<form method="POST" action="{{route('member.store')}}">

導線(store→index)

controllerで、リダイレクトを記述済です。

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/create にアクセスし、値を入力して送信すると、member/indexにリダイレクトされ、membersテーブルに値が入っている事を確認します。
Ctrl+Cで簡易サーバーを終了します。

詳細表示(show)

routingの追加

/member/show/idにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');
  Route::post('store', 'MemberController@store')->name('member.store');

  //追加
  Route::get('show/{id}', 'MemberController@show')->name('member.show');
});

controllerの編集

指定したIDのメンバーの詳細ページを表示する処理をします。

app\Http\Controllers\MemberController.php
public function show($id)
  {
    $member=Member::find($id);

    return view('member/show', compact('member'));
  }

viewの新規作成

resources\views\member\show.blade.php
<h1>詳細表示</h1>

<div>
名前
{{$member->name}}
</div>

<div>
電話番号
{{$member->telephone}}
</div>

<div>
メールアドレス
{{$member->email}}
</div>

導線(index→show)

一覧表示画面に、1カラム増やして詳細画面へのリンクを追加します。

resources\views\member\index.blade.php
<table>
<tr>
<th>ID</th>
<th>名前</th>
<th>電話番号</th>
<th>メールアドレス</th>
<th>詳細</th>
</tr>
@foreach($members as $member)
<tr>
<td>{{$member->id}}</td>
<td>{{$member->name}}</td>
<td>{{$member->telephone}}</td>
<td>{{$member->email}}</td>
<td><th><a href="{{route('member.show',['id'=>$member->id])}}">詳細</a></th></td>
</tr>
@endforeach
</table>

導線(show→index)

resources\views\member\show.blade.php
<a href="{{ route('member.index') }}">{{ __('一覧に戻る') }}</a>

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/index にアクセスし、詳細を押すと詳細画面が表示されることを確認します。
Ctrl+Cで簡易サーバーを終了します。

編集(edit)

routingの追加

/member/edit/idにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');
  Route::post('store', 'MemberController@store')->name('member.store');
  Route::get('show/{id}', 'MemberController@show')->name('member.show');

  //追加
  Route::get('edit/{id}', 'MemberController@edit')->name('member.edit');
});

controllerの編集

app\Http\Controllers\MemberController.php
public function edit($id)
  {
    $member=Member::find($id);

    return view('member/edit', compact('member'));
  }

viewの新規作成

resources\views\member\edit.blade.php
<h1>編集</h1>

 <form method="POST" action="">
  @csrf

 <div>
  名前
  <input type="text" name=name value="{{$member->name}}">
  </div>

  <div>
  電話番号
  <input type="text" name=telephone value="{{$member->telephone}}">
  </div>

  <div>
  メールアドレス
  <input type="text" name=email value="{{$member->email}}">
  </div>


  <input type="submit" value="更新する">

  </form>

導線(show→edit)

resources\views\member\show.blade.php
//追加
<a href="{{route('member.edit',['id'=>$member->id])}}">{{ __('編集') }}</a>

導線(edit→show)

resources\views\member\edit.blade.php
//追加
<a href="{{route('member.show',['id'=>$member->id])}}">{{ __('詳細に戻る') }}</a>

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/index にアクセスし、詳細→編集と進む編集フォームが表示されることを確認します。
(この時点では、更新ボタンを押してもエラーになります。)

更新(update)

編集画面で「更新」ボタンを押した時の動作を設定していきます。

routingの追加

/member/update/idにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');
  Route::post('store', 'MemberController@store')->name('member.store');
  Route::get('show/{id}', 'MemberController@show')->name('member.show');
  Route::get('edit/{id}', 'MemberController@edit')->name('member.edit');

  //追加
  Route::post('update/{id}', 'MemberController@update')->name('member.update');
});

controllerの編集

app\Http\Controllers\MemberController.php
public function update(Request $request, $id)
  {
    $member=Member::find($id);

    $member->name=$request->input('name');
    $member->telephone=$request->input('telephone');
    $member->email=$request->input('email');

    //DBに保存
    $member->save();

    //処理が終わったらmember/indexにリダイレクト
    return redirect('member/index');
}

viewの新規作成

なし

導線(edit→update)

editの送信ボタンの送信先を指定します。

resources\views\member\edit.blade.php
//<form method="POST" action="">
//↓
<form method="POST" action="{{route('member.update',['id' =>$member->id])}}">

導線(update→index)

controllerでリダイレクト済

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/index にアクセスし、詳細画面→編集画面と移動し、値を変更して「更新」ボタンを押し、/member/indexのデータが変更されていることを確認します。
Ctrl+Cで簡易サーバーを終了します。

削除(destroy)

routingの追加

/member/destroy/idにアクセスした場合のルーティングを追加します。

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index', 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');
  Route::post('store', 'MemberController@store')->name('member.store');
  Route::get('show/{id}', 'MemberController@show')->name('member.show');
  Route::get('edit/{id}', 'MemberController@edit')->name('member.edit');
  Route::post('update/{id}', 'MemberController@update')->name('member.update');

  //追加
  Route::post('destroy/{id}', 'MemberController@destroy')->name('member.destroy');
});

controllerの編集

指定のIDを削除する処理を書きます。

app\Http\Controllers\MemberController.php
public function destroy($id)
  {
    $member=Member::find($id);

    $member->delete();

    return redirect('member/index');
  }

viewの新規作成

なし

導線(show→destroy)

resources\views\member\show.blade.php
//追加
<form method="POST" action="{{route('member.destroy',['id'=>$member->id])}}">
  @csrf
  <button type="submit">削除</button>
</form>

導線(destroy→index)

controllerでリダイレクト済

確認

簡易サーバーを起動します。

terminal
php artisan serve

ブラウザで http://127.0.0.1:8000/member/index にアクセスし、詳細画面に移動し、「削除」ボタンを押し、/member/indexのデータが削除されていることを確認します。
Ctrl+Cで簡易サーバーを終了します。

バリデーションの準備

エラーメッセージの日本語化

resources/lang/に下記のjaフォルダをenフォルダと同じ階層に配置します。
https://github.com/minoryorg/laravel-resources-lang-ja
※jaフォルダ内のファイルの編集でさらにメッセージのカスタマイズができます。

resources\lang\ja\validation.php
//'attributes' => [],
//↓
'attributes' => ['email'=>'メールアドレス',
'name'=>'名前'
],

バリデーション(新規保存)

form requestの作成

terminal
php artisan make:request StoreMember

app\Http\Requests\StoreMember.phpが新規作成されます。

form requestの編集

バリデーションのルールを指定します。

app\Http\Requests\StoreMember.php
//追加
use Illuminate\Validation\Rule;

public function authorize()
  {
    //return false;
    //↓falseをtrueに変更
    return true;
  }

public function rules()
  {
    return [

      //追加
      'name' => [
        'string',
        'required',
        'max:20'
         ],

      'telephone' => [
        'string',
        'nullable',
        'max:13',
        'unique:members'
        ],

      'email' => [
        'nullable',
        'max:255',
        'email',
        'unique:members'
        ]
    ];
  }
キーワード 内容
required 必須
max 最大長
unique:テーブル名 指定のテーブルでユニーク
nullable null許容
accepted チェックされている
string 文字列型
email email型
url url型

controller

app\Http\Controllers\MemberController.php
//追加
use App\Http\Requests\StoreMember;


//public function store(Request $request)
//↓変更
public function store(StoreMember $request)

view

エラーメッセージを表示させたい場所にエラーメッセージを配置します。

resources\views\member\create.blade.php
<form method="POST" action="{{route('member.store')}}">
  @csrf

  <div>
    <label for="form-name">名前</label>

    // <input type="text" name="name" id="form-name" required>
    //↓valueを追加して入力値を保持させます。
    <input type="text" name="name" id="form-name" required value="{{old('name')}}">

    //追加
    @error('name')
    {{$message}}
    @enderror

  </div>

  <div>
    <label for="form-tel">電話番号</label>

    //<input type="tel" name="telephone" id="form-tel">
    //↓valueを追加して入力値を保持させます。
    <input type="tel" name="telephone" id="form-tel" value="{{old('telephone')}}">

   //追加
   @error('telephone')
   {{$message}}
   @enderror

  </div>

  <div>

    <label for="form-email">メールアドレス</label>

    //<input type="email" name="email" id="form-email">
    //↓valueを追加して入力値を保持させます。
    <input type="email" name="email" id="form-email" value="{{old('email')}}">

    //追加
    @error('email')
    {{$message}}
    @enderror

  </div>

  <button type="submit">送信</button>

</form>

バリデーション(上書き保存)

新規登録のバリデーションのままでは、ユニークにする電話番号と、メールアドレスを弾いてしまうので、変更が必要です。

form requestの作成

terminal
php artisan make:request UpdateMember

app\Http\Requests\UpdateMember.phpが新規作成されます。

form requestの編集

新規作成のバリデーションとほぼ同じですが、既存の値も許可するように変更します。

app\Http\Requests\UpdateMember.php
//追加
use Illuminate\Validation\Rule;

public function authorize()
  {
    //return false;
    //↓falseをtrueに変更
    return true;
  }

public function rules()
  {
    return [

      //追加
      'name' => [
        'string',
        'required',
        'max:20'
        ],

      'telephone' => [
         'string',
         'nullable',
         'max:13',

         //既存の値も許可
         Rule::unique('members')->ignore($this->id)
       ],

      'email' => [
        'nullable',
        'max:255',
        'email',

         //既存の値も許可
         Rule::unique('members')->ignore($this->id)
         ]

     ];
   }

controller

app\Http\Controllers\MemberController.php
//追加
use App\Http\Requests\UpdateMember;

//public function update(Request $request, $id)
//↓変更
public function update(UpdateMember $request, $id)

view

エラーメッセージを表示させたい場所にエラーメッセージを配置します。

resources\views\member\edit.blade.php
<form method="POST" action="{{route('member.update',['id' =>$member->id])}}">
 @csrf

  <div>
    名前
    <input type="text" name=name value="{{$member->name}}">
    @error('name')
    {{$message}}
    @enderror
  </div>

  <div>
    電話番号
    <input type="text" name=telephone value="{{$member->telephone}}">
    @error('telephone')
    {{$message}}
    @enderror
  </div>

  <div>
    メールアドレス
    <input type="text" name=email value="{{$member->email}}">
    @error('email')
    {{$message}}
    @enderror
  </div>

  <input type="submit" value="更新する">

</form>

ページネーション

controller

一覧表示の件数が増えてきたら、ページを分けます。

app\Http\Controllers\MemberController.php
public function index()
  {
    $members=DB::table('members')
      ->select('id', 'name', 'telephone', 'email')
      //->get();
      //↓ 1ページに表示する件数を指定
      ->paginate(20);

      //viewを返す(compactでviewに$membersを渡す)
      return view('member/index', compact('members'));
  }

view

一覧画面にページ送りのUIを追加します。

resources\views\member\index.blade.php
//追加
{{$members->links()}}

記述としては1行ですが、下記のようにhtmlが生成されますので、CSSで形を整えてください。

html
<nav>
  <ul class="pagination">

    <li class="page-item disabled" aria-disabled="true" aria-label="« Previous"><span class="page-link" aria-hidden="true">‹</span></li>
    <li class="page-item active" aria-current="page">
      <span class="page-link">1</span>
    </li>
    <li class="page-item">
      <a class="page-link" href="http://127.0.0.1:8000/member/index?page=2">2</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="http://127.0.0.1:8000/member/index?page=2" rel="next" aria-label="Next »">›</a>
    </li>

  </ul>
</nav>

検索機能

routingの追加

route/web.php
Route::group(['prefix'=>'member'], function () {
  Route::get('index' 'MemberController@index')->name('member.index');
  Route::get('create', 'MemberController@create')->name('member.create');
  Route::post('store', 'MemberController@store')->name('member.store');
  Route::get('show/{id}', 'MemberController@show')->name('member.show');
  Route::get('edit/{id}', 'MemberController@edit')->name('member.edit');
  Route::post('update/{id}', 'MemberController@update')->name('member.update');
  Route::post('destroy/{id}', 'MemberController@destroy')->name('member.destroy');

  //追加
  Route::get('search', 'MemberController@search')->name('member.search');
});

controllerの編集

app\Http\Controllers\MemberController.php
public function search(Request $request)
  {
    $serach=$request->input('q');

    $query=DB::table('members');

    //検索ワードの全角スペースを半角スペースに変換
    $serach_spaceharf=mb_convert_kana($serach, 's');


    //検索ワードを半角スペースで区切る
    $keyword_array=preg_split('/[\s]+/', $serach_spaceharf, -1, PREG_SPLIT_NO_EMPTY);

    //検索ワードをループで回してマッチするレコードを探す
    foreach ($keyword_array as $keyword) {
        $query->where('name', 'like', '%'.$keyword.'%');
      }

    $query->select('id', 'name', 'telephone', 'email');
    $members=$query->paginate(20);

    return view('member/index', compact('members'));
  }

viewの編集

一覧表示画面に検索フォームを追加します。

resources\views\member\index.blade.php
//追加
<form method="GET" action="{{route('member.search')}}">
  @csrf
  <div>
    <label for="form-search">検索</label>
    <input type="search" name="q" id="form-search">
  </div>

  <button type="submit">検索</button>

</form>
41
47
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
47