Help us understand the problem. What is going on with this article?

Laravel5.7: usersのCRUD機能を実装する

More than 1 year has passed since last update.

usersテーブルに関するCRUD機能を実装します。

親記事

Laravel 5.7で基本的なCRUDを作る - Qiita

usersのEloquentモデルを生成する

:link: readouble.com: モデル定義

なお、usersテーブルの場合はapp/User.phpが既に存在するので、モデル生成は不要です。

usersのコントローラーを生成する

今回は、典型的なCRUD機能を提供してくれるリソースコントローラを利用させてもらいます。
:link: readouble.com: リソースコントローラ

PowerShell
> php artisan make:controller UserController --resource

app/Http/Controllers/UserController.phpが生成され、CRUDに関するアクションメソッドも自動で定義されています。
あとは中身の処理を書くだけです。

ルーティングを設定する

routes/web.php
Route::resource('users', 'UserController');

上の一行で、下記のようにCRUDに関するルートがまとめて設定されます。

動詞 URI アクション ルート名
GET /users index users.index
GET /users/create create users.create
POST /users store users.store
GET /users/{user} show users.show
GET /users/{user}/edit edit users.edit
PUT/PATCH /users/{user} update users.update
DELETE /users/{user} destroy users.destroy

Artisanコマンドでルートの設定を確認することもできます。

PowerShell
> php artisan route:list

Eloquentモデルをインポートする

コントローラ内で頻繁に使うことになるので、モデルをインポートしておきます。

app/Http/Controllers/UserController.php
  use Illuminate\Http\Request;
+ use App\User;

  class UserController extends Controller
  {

次からは、CRUDの機能をひとつひとつ実装していきます。

index

:link: readouble.com: モデルの取得

ユーザーを一覧表示します。
以前の記事で生成したデータが表示されます。

URL例: http://<APP_URL>/users
001.png

コントローラ

app/Http/Controllers/UserController.php
    public function index()
    {
        $users = User::all();
        return view('users.index', ['users' => $users]);
    }

ビュー

以前の記事で作ったレイアウトを利用します。

resources/views/users/index.blade.php
@php
    $title = __('Users');
@endphp
@extends('layouts.my')
@section('content')
<div class="container">
    <h1>{{ $title }}</h1>
    <div class="table-responsive">
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>{{ __('ID') }}</th>
                    <th>{{ __('Name') }}</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($users as $user)
                    <tr>
                        <td>{{ $user->id }}</td>
                        <td><a href="{{ url('users/'.$user->id) }}">{{ $user->name }}</a></td>
                    </tr>
                @endforeach
            </tbody>
        </table>
    </div>
</div>
@endsection

手軽に見栄えを整えるためにBootstrapを利用しています。
また、後で多言語化に対応させるので、あらかじめ__メソッド内に文章を記述するようにしています。
:link: readouble.com: 翻訳文字列の取得

-    Name
+    {{ __('Name') }}

show

:link: readouble.com: 1モデル/集計の取得

1件だけを表示します。

URL例: http://<APP_URL>/users/show/1
002.png

コントローラ

app/Http/Controllers/UserController.php
    /**
     * Display the specified resource.
     *
     * @param  \App\User $user
     * @return \Illuminate\Http\Response
     */
    public function show(User $user)
    {
        return view('users.show', ['user' => $user]);
    }

「モデル結合ルート」を利用して簡潔に記述するため、showメソッドの引数は$idではなくUser $userとします。
:link: readouble.com: モデル結合ルート (Route Model Binding)

ビュー

resources/views/users/show.blade.php
@php
    $title = __('User') . ': ' . $user->name;
@endphp
@extends('layouts.my')
@section('content')
<div class="container">
    <h1>{{ $title }}</h1>

    {{-- 編集・削除ボタン --}}
    <div>
        <a href="{{ url('users/'.$user->id.'/edit') }}" class="btn btn-primary">
            {{ __('Edit') }}
        </a>
        {{-- 削除ボタンは後で正式なものに置き換えます --}}
        <a href="#" class="btn btn-danger">
            {{ __('Delete') }}
        </a>
    </div>

    {{-- ユーザー1件の情報 --}}
    <dl class="row">
        <dt class="col-md-2">{{ __('ID') }}</dt>
        <dd class="col-md-10">{{ $user->id }}</dd>
        <dt class="col-md-2">{{ __('Name') }}</dt>
        <dd class="col-md-10">{{ $user->name }}</dd>
        <dt class="col-md-2">{{ __('E-Mail Address') }}</dt>
        <dd class="col-md-10">{{ $user->email }}</dd>
    </dl>
</div>
@endsection

create, store

:link: readouble.com: Inserts

1件を新規追加します。
後の章でバリデーション・ルールを設定するまでは、パスワードの2回入力による確認は機能しません。

URL例: http://<APP_URL>/users/create
090.png

コントローラ

app/Http/Controllers/UserController.php
    // 追加用のフォーム画面へ移動
    public function create()
    {
        return view('users.create');
    }

    // 実際の追加処理
    // 終わったら、作ったばかりのユーザーのページへ移動
    public function store(Request $request)
    {
        $user = new User;
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = $request->password;
        $user->save();
        return redirect('users/'.$user->id);
    }

ビュー

resources/views/users/create.blade.php
@php
    $title = __('Create User');
@endphp
@extends('layouts.my')
@section('content')
<div class="container">
    <h1>{{ $title }}</h1>
    <form action="{{ url('users') }}" method="post">
        @csrf {{-- CSRF保護 --}}
        @method('POST') {{-- 疑似フォームメソッド --}}
        <div class="form-group">
            <label for="name">{{ __('Name') }}</label>
            <input id="name" type="text" class="form-control" name="name" required autofocus>
        </div>
        <div class="form-group">
            <label for="email">{{ __('E-Mail Address') }}</label>
            <input id="email" type="email" class="form-control" name="email" required>
        </div>
        <div class="form-group">
            <label for="password">{{ __('Password') }}</label>
            <input id="password" type="password" class="form-control" name="password" required>
        </div>
        <div class="form-group">
            <label for="password_confirmation">{{ __('Confirm Password') }}</label>
            <input id="password_confirmation" type="password" class="form-control" name="password_confirmation" required>
        </div>
        <button type="submit" name="submit" class="btn btn-primary">{{ __('Submit') }}</button>
    </form>
</div>
@endsection

:link: readouble.com: CSRF保護
:link: readouble.com: 疑似フォームメソッド

edit, update

:link: readouble.com: Updates

1件を更新します。
今のところ、メールアドレスとパスワードは変更できません。

URL例: http://<APP_URL>/users/2/edit
010.png

コントローラ

app/Http/Controllers/UserController.php
    // 更新用フォーム画面へ移動
    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\User $user
     * @return \Illuminate\Http\Response
     */
    public function edit(User $user)
    {
        return view('users.edit', ['user' => $user]);
    }

    // 実際の更新処理
    // 終わったら、そのユーザのページへ移動
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\User $user
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, User $user)
    {
        $user->name = $request->name;
        $user->save();
        return redirect('users/'.$user->id);
    }

ビュー

method_field()PUTを指定する以外はcreate.blade.phpと同じです。

resources/views/users/edit.blade.php
@php
    $title = __('Edit').': '.$user->name;
@endphp
@extends('layouts.my')
@section('content')
<div class="container">
    <h1>{{ $title }}</h1>
    <form action="{{ url('users/'.$user->id) }}" method="post">
        @csrf
        @method('PUT')
        <div class="form-group">
            <label for="name">{{ __('Name') }}</label>
            <input id="name" type="text" class="form-control" name="name" value="{{ $user->name }}" required autofocus>
        </div>
        <button type="submit" name="submit" class="btn btn-primary">{{ __('Submit') }}</button>
    </form>
</div>
@endsection

destroy

:link: readouble.com: モデル削除

1件を削除します。
現時点では、確認も何もなくいきなり削除します。

コントローラ

app/Http/Controllers/UserController.php
    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\User $user
     * @return \Illuminate\Http\Response
     */
    public function destroy(User $user)
    {
        $user->delete();
        return redirect('users');
    }

ビュー

削除ボタンは色々な場所で使うので、コンポーネントとしてまとめておきます。
:link: readouble.com: コンポーネントとスロット

resources/views/components/btn-del.blade.php
<form style="display:inline" action="{{ url($table.'/'.$id) }}" method="post">
    @csrf
    @method('DELETE')
    <button type="submit" class="btn btn-danger">
        {{ __('Delete') }}
    </button>
</form>

先ほど作ったshowページの削除ボタンと置き換えます。

resources/views/users/show.blade.php
-         {{-- 削除ボタンは後で正式なものに置き換えます --}}
-         <a href="#" class="btn btn-danger">
-             {{ __('Delete') }}
-         </a>
+         @component('components.btn-del')
+             @slot('table', 'users')
+             @slot('id', $user->id)
+         @endcomponent

完了

ログインもバリデーションもありませんが、とりあえずCRUDの根幹はできあがりました。

sutara79
宮崎 雄策。1979年生まれ。PHP(Laravel)、 JavaScript(jQuery)、英語を勉強中の文系Webプログラマ。
https://ja.gravatar.com/sutara79
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした