Edited at

Laravel5.6入門 基本CRUD操作を体で覚える


Laravel5.6入門 基本CRUD操作を体で覚える


はじめに

プログラミングは「習うより慣れろ」ということで、アプリケーションの基本のCRUDをLaravelでやってみた。

※ 書いているのは生意気にもLaravel歴一週間程度の初心者です。

MVCアーキテクチャのフレームワークだと作業手順としては、ものすごくざっくりだと以下のような流れになるんじゃないかと思う。


  1. モデル作成

  2. マイグレーション作成

  3. コントローラー作成

  4. ルーティング作成

  5. ビュー作成


対象となる読者


  • Laravelの環境構築が一通り終わっていて、とりあえず触ってみようかなって方

  • 見た目とかは一切気にせずとりあえずCRUDだけやってみたい


環境


  • php 7.1

  • sqlite

  • laravel 5.6.3


ささっと進めたかったので、sqliteを使います。



準備

プロジェクト名は本当に適当なのでsampleで進めてしまいます。

// laravelコマンドを使える場合は以下

$ laravel new sample

// 使えない場合はcomposer経由で
$ composer create-project laravel/laravel sample

// 生成したsampleディレクトリまで移動
$ cd sample

// 試しにphpのビルトインサーバーを起動してみる
$ php artisan serve

LaravelのWelcomeページが表示されて入ればOK。

サーバーを止めるのは、control+cで停止させることが出来ます。


sqliteを使えるように設定する

sampleディレクトリで以下を実行。

$ touch database/database.sqlite

.envを編集

# DB_CONNECTIONをsqliteに

DB_CONNECTION=sqlite
# 以下をコメントアウト
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=homestead
# DB_USERNAME=homestead
# DB_PASSWORD=secret

以上でsqliteが使えるようになります。


Laravelで使えるコマンドを確認しておく

Laravelはバージョンによって微妙にコマンドが違っているので、事前にコマンドを確認しておきましょう。

Laravelではコマンドリストを確認できるコマンドがあり、親切な説明が加えられているので、開発前に眺めておくことをオススメします。

引数の使い方もこちらで参照出来ます。

// 以下でコマンドリストを確認できます。

$ php artisan

// 以下でも出来ます
$ php artisan list


モデルとマイグレーションを作成

今回はAricleモデルというケースで進めていきます。

モデルを作る場合は、php artisan make:model モデル名でモデルファイルを作成することが出来ます。

今回は、make:modelコマンドの引数オプションの-mを使い作成したモデルに関連したマイグレーションファイルを同時に作成します。

$ php artisan make:model Article -m

以上を実行すると、以下のようなメッセージが表示されます。

Model created successfully.

Created Migration: 2018_02_16_021144_create_articles_table


マイグレーションファイルを編集

マイグレーションファイルを作成できたら、database/migrationsディレクトリ内に先ほど生成されたマイグレーションファイルが格納されているかと思います。

デフォルトで2つのマイグレーションファイルが入っているので、日付を確認して、生成されたファイルを開きます。

自分の場合、2018_02_16_012154_create_article_table.phpという名前でした。

titleカラムとbodyカラムを追加するように編集をしましょう。

<?php

public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
// 以下の二行を追加
$table->string('title');
$table->text('body');
$table->timestamps();
});
}

$table->データ型('カラム名');となるようです。

以上が出来たら、php artisan migrateでマイグレーションファイルの内容をデータベースに反映させます。


コントローラーを作る

モデルまでが完成したので、コントローラーを作っていきます。

コントローラー作成のコマンドはphp artisan make:controller コントローラー名です。

コントローラーは複数形で定義しないといけないという規約があります。

今回は-rオプションを用いて、Resourcefulなアクションを自動で定義したコントローラーを生成します。

$ php artisan make:controller ArticlesController -r

以上でapp/Http/ControllersディレクトリにArticlesController.phpが作成されているかと思います。

中身を見てみると、以下のようにResourcefulなアクションが定義されているかと思います。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;
class ArticlesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/

public function index()
{
//
}

/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/

public function create()
{
//
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/

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

/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/

public function show($id)
{
//
}

/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/

public function edit($id)
{
//
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/

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

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/

public function destroy($id)
{
//
}
}


ルーティングを定義する

コントローラーの作成でResourcefulなアクションを定義したので、ルーティングでもResourcefulなルーティングを定義していきます。

Laravel5.6系ではroutesというディレクトリの中に、以下の4つのファイルが格納されています。


  • api.php

  • channels.php

  • console.php

  • web.php

webアプリケーションを作成したい場合は、web.phpに記述していくことになるでしょう。

APIであればapi.php

とてもわかりやすい...

今回はweb.phpを使っていきます。

web.phpを開き

<?php

Route::get('/', function () {
return view('welcome');
});

// 以下を追加
Route::resource('articles', 'ArticlesController');

以上のように編集します。

以上でアプリケーションで使うURIパターンを定義したのですが、定義したURIを確認したいことが度々あります。

その場合は、以下のコマンドで定義したルーティングを確認出来ます。

$ php artisan route:list

上記を実行すると、以下のように表示されました。

+--------+-----------+-----------------------------+------------------+-------------------------------------------------+--------------+

| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+-----------------------------+------------------+-------------------------------------------------+--------------+
| | GET|HEAD | api/user | | Closure | api,auth:api |
| | GET|HEAD | articles | articles.index | App\Http\Controllers\ArticlesController@index | web |
| | POST | articles | articles.store | App\Http\Controllers\ArticlesController@store | web |
| | GET|HEAD | articles/create | articles.create | App\Http\Controllers\ArticlesController@create | web |
| | GET|HEAD | articles/{article} | articles.show | App\Http\Controllers\ArticlesController@show | web |
| | PUT|PATCH | articles/{article} | articles.update | App\Http\Controllers\ArticlesController@update | web |
| | DELETE | articles/{article} | articles.destroy | App\Http\Controllers\ArticlesController@destroy | web |
| | GET|HEAD | articles/{article}/edit | articles.edit | App\Http\Controllers\ArticlesController@edit | web |
+--------+-----------+-----------------------------+------------------+-------------------------------------------------+--------------+


seederを使ってダミーデータを入れる

ここまでで、モデル・コントローラー・ルーティングまでやったのですが、表示の確認などをしたいので、ダミーデータを入れておきましょう。

今回はLaravelのmake:seederコマンドを作って、Articleモデルにダミーデータを入れます。

// seederファイルを作成する

$ php artisan make:seeder ArticlesTableSeeder

以上を実行すると、database/seedsディレクトリにArticlesTableSeeder.phpというファイルが生成される。このArticlesTableSeeder.phpを編集していく。

<?php

public function run()
{
// articlesテーブルにデータをinsert
DB::table('articles')->insert([
[
'title' => 'タイトル1',
'body' => '内容1'
],
[
'title' => 'タイトル2',
'body' => '内容2'
],
[
'title' => 'タイトル3',
'body' => '内容3'
],
]);
}

以上を記述したら、database/seeds/DatabaseSeeder.phpを編集する。

<?php

public function run()
{
// $this->call(UsersTableSeeder::class);
// 以下を追記
$this->call(ArticlesTableSeeder::class);
}

seederファイルを追加したら、DatabaseSeeder.phprun(){}内に、$this->call(seederファイル名::class)とすればいいっぽい

以上が出来たら、php artisan db:seedを実行するとテストデータが投入されます。

テストデータが入ったか確認をしてみます。

ターミナルで以下を実行します。

$ php artisan tinker

上記を実行すると、以下のようなプロンプトが起動します。

Psy Shell v0.8.17 (PHP 7.1.8 — cli) by Justin Hileman

>>>

Articleモデルから全てのレコードを取得してみたいので、以下を実行します。

>>> $a = App\Article::all();

上記を実行すると、以下のように返ってくるかと思います。

=> Illuminate\Database\Eloquent\Collection {#780

all: [
App\Article {#781
id: "1",
title: "タイトル1",
body: "内容1",
created_at: null,
updated_at: null,
},
App\Article {#782
id: "2",
title: "タイトル2",
body: "内容2",
created_at: null,
updated_at: null,
},
App\Article {#783
id: "3",
title: "タイトル3",
body: "内容3",
created_at: null,
updated_at: null,
},
],
}

テストデータの挿入が確認出来たので、

>>> exit

してtinkerを終了する


一覧を表示させる

テストデータも入れたので、表示を確認してみたいと思います。

app/Http/Controllers/ArticlesController.phpを開きます。

indexアクションを一覧として使いたいので、index(){}内に処理を書いていきましょう。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
// 以下を忘れずに。このコントローラーで使用したいモデルがあれば随時追加をしていくっぽい
use App\Article;
class ArticlesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/

public function index()
{
// $articles変数にArticleモデルから全てのレコードを取得して、代入
$articles = Article::all();
return $articles;
}

以上を記述したら、php artisan serveでビルトインサーバを起動し、http://localhost:8000/articles にアクセスしてみましょう。

まだビューを用意していないので、以下のようにJSONで返ってくるかと思います。

[{"id":1,"title":"\u30bf\u30a4\u30c8\u30eb1","body":"\u5185\u5bb91","created_at":null,"updated_at":null},{"id":2,"title":"\u30bf\u30a4\u30c8\u30eb2","body":"\u5185\u5bb92","created_at":null,"updated_at":null},{"id":3,"title":"\u30bf\u30a4\u30c8\u30eb3","body":"\u5185\u5bb93","created_at":null,"updated_at":null}]


ビューを用意する

ビューはresources/viewsディレクトリ内に格納していきます。

まずは基本的なレイアウトを用意したいので、

resources/viewsディレクトリ内にlayoutsディレクトリを作成し、中にapplication.blade.phpを作成します。

bladeというのはlaravelのテンプレートファイルを表す拡張子です。

resources/views/layouts/application.blade.phpに以下を入力

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>@yield('title')</title>
</head>
<body>
@yield('content')
</body>
</html>

次はresources/viewsディレクトリ内にarticlesディレクトリを作成し、その中にindex.blade.phpを作成。

index.blade.phpを編集していきます。

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとにtitleタグの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<h1>ほげ</h1>
@endsection

上記のままでは、テンプレートファイルが呼ばれないので、コントローラーを修正していきます。

app/Http/Controllers/ArticlesController.phpを開き、indexアクションを修正します。

php

<?php

public function index()

{

$articles = Article::all();

// 以下をコメントアウト

// return $articles;

// 以下を追加

return view('articles.index');

}

以上の状態で、http://localhost:8000/articles をみてみましょう。

するとブラウザに「ほげ」という文字が表示され、articles/index.blade.phpの内容が表示されているのがわかるかと思います。

ここでは、bladeテンプレートの詳しい構文の説明などは省きたいと思います。

確認をしたい方は公式ドキュメント を参照ください。


ビューでコントローラーの値を表示させる

ArticlesController.phpで全てのレコードを取得しているので、ビュー側でそれらを表示させてみたいと思います。

resources/views/articles/index.blade.phpを開き修正します。

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
@foreach ($articles as $article)
<h4>{{$article->title}}</h4>
<p>{{$article->body}}</p>
<hr>
@endforeach
@endsection

このままでは、まだコントローラーで取得した$articlesは使えないので、またArticlesController.phpindexアクションを修正します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;
class ArticlesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/

public function index()
{
$articles = Article::all();
// return $articles;
// 以下のように修正
return view('articles.index', ['articles' => $articles]);
}

これでテンプレートを使って取得したレコード全件を表示させることが出来る。

http://localhost:8000/articles を確認すると、表示が確認出来るかと思います。


詳細ページを作る

まずはルーティングを確認します。

php artisan route:listでルーティングを確認し、showアクションの部分を探します。

自分の環境下では以下のようになっていました。



GET|HEAD | articles/{article} | articles.show | App\Http\Controllers\ArticlesController@show | web |

一覧ページに詳細ページへのリンクをつけたいので、一覧ページを編集。

resources/views/articles/index.blade.phpを編集します。

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
@foreach ($articles as $article)
<h4>{{$article->title}}</h4>
<p>{{$article->body}}</p>
{{-- 以下を追記 --}}
<a href="/articles/{{$article->id}}">詳細を表示</a>
<hr>
@endforeach
@endsection

app/Http/Controllers/ArticlesController.phpshowアクションを編集します。

<?php

// showアクション以外は省略
public function show($id)
{
// 引数で受け取った$idを元にfindでレコードを取得
$article = Article::find($id);
// viewにデータを渡す
return view('articles.show', ['article' => $article]);
}

詳細ページのビューを作成します。

resources/views/articlesディレクトリにshow.blade.phpファイルを作成し、以下を入力していきます。

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事詳細')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<h1>{{$article->title}}</h1>
<p>{{$article->body}}</p>
<br><br>
<a href="/articles">一覧に戻る</a>
@endsection


新規作成機能を作る

php artisan route:listでルーティングを確認する。

POST | articles | articles.store | App\Http\Controllers\ArticlesController@store   |

GET|HEAD | articles/create | articles.create | App\Http\Controllers\ArticlesController@create |

resourceで定義したルーティングだと、/articles/createでアクセスをしたページが新規作成用のビューで/articlesにPOSTするとレコードを新規作成出来る

一覧ページに新規作成用のリンクを貼っておく

resources/views/articles/index.blade.phpを以下のように修正

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<div>
<a href="/articles/create">新規作成</a>
</div>
@foreach ($articles as $article)
<h4>{{$article->title}}</h4>
<p>{{$article->body}}</p>
<a href="/articles/{{$article->id}}">詳細を表示</a>
<hr>
@endforeach
@endsection

次にresources/views/articlescreate.blade.phpを作成する

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '新規作成')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<form action="/articles" method="post">
{{-- 以下を入れないとエラーになる --}}
{{ csrf_field() }}
<div>
<label for="title">タイトル</label>
<input type="text" name="title" placeholder="記事のタイトルを入れる">
</div>
<div>
<label for="body">内容</label>
<textarea name="body" rows="8" cols="80" placeholder="記事の内容を入れる"></textarea>
</div>
<div>
<input type="submit" value="送信">
</div>
</form>
@endsection

app/Http/Controllers/ArticlesController.phpのコントローラーを修正する

新規作成に関連するアクションはcreatestoreのアクションなので、コントローラーもその二つのアクションを編集する。

createアクションはビューを表示するだけなので、以下のようになる。

<?php

public function create()
{
return view('articles.create');
}

storeアクションはcreateでPOSTされたデータを保存する処理を書く必要がある。


※ 今回はバリデーションなんかは書きません


<?php

public function store(Request $request)
{
// モデルからインスタンスを生成
$article = new Article;
// $requestにformからのデータが格納されているので、以下のようにそれぞれ代入する
$article->title = $request->title;
$article->body = $request->body;
// 保存
$article->save();
// 保存後 一覧ページへリダイレクト
return redirect('/articles');
}

これで新規作成機能は完成です。


編集機能を作る

ルーティングを確認する。

PUT|PATCH | articles/{article} | articles.update | App\Http\Controllers\ArticlesController@update

GET|HEAD | articles/{article}/edit | articles.edit | App\Http\Controllers\ArticlesController@edit

articles/{article}/editにアクセスをすれば編集ページが呼ばれ、articles/{article}にPUT/PATCHメソッドでアクセスをすれば更新処理が呼ばれるようになっているので、それに沿って作っていく


一覧ページに編集用のリンクを追加

resources/views/articles/index.blade.phpを編集する

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<div>
<a href="/articles/create">新規作成</a>
</div>
@foreach ($articles as $article)
<h4>{{$article->title}}</h4>
<p>{{$article->body}}</p>
<a href="/articles/{{$article->id}}">詳細を表示</a>
<a href="/articles/{{$article->id}}/edit">編集する</a>
<hr>
@endforeach
@endsection


詳細ページにも追加する

resources/views/articles/show.blade.phpを編集する

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事詳細')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<h1>{{$article->title}}</h1>
<p>{{$article->body}}</p>
<br><br>
<a href="/articles/{{$article->id}}/edit">編集する</a>
<a href="/articles">一覧に戻る</a>
@endsection


editアクションを編集

app/Http/Controllers/ArticlesController.phpのeditアクションを編集

<?php

public function edit($id)
{
$article = Article::find($id);
return view('articles.edit', ['article' => $article]);
}


編集ページを作成する

resources/views/articlesディレクトリにedit.blade.phpを作成

その中に以下を記述


ここで詰まったのが、HTMLのフォームでHTTPメソッドのPATCHをサポートしていないので、<input type="hidden" name="_method" value="patch">をform内に配置する必要があった


{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '編集')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<form action="/articles/{{$article->id}}" method="post">
{{ csrf_field() }}
<div>
<label for="title">タイトル</label>
<input type="text" name="title" placeholder="記事のタイトルを入れる" value="{{$article->title}}">
</div>
<div>
<label for="body">内容</label>
<textarea name="body" rows="8" cols="80" placeholder="記事の内容を入れる">{{$article->body}}</textarea>
</div>
<div>
<input type="hidden" name="_method" value="patch">
<input type="submit" value="更新">
</div>
</form>
@endsection


updateアクションを編集する

app/Http/Controllers/ArticlesController.phpのupdateアクションを編集

<?php

public function update(Request $request, $id)
{
// idを元にレコードを検索して$articleに代入
$article = Article::find($id);
// editで編集されたデータを$articleにそれぞれ代入する
$article->title = $request->title;
$article->body = $request->body;
// 保存
$article->save();
// 詳細ページへリダイレクト
return redirect("/articles/".$id);
}


削除機能を作る


ルーティングを確認

DELETE | articles/{article} | articles.destroy | App\Http\Controllers\ArticlesController@destroy

上記のように定義されていた。

なので、/articles/{article}にHTTPメソッドDELETEでアクセスをさせるように作ればいい


一覧に削除リンクを貼る

resources/views/articles/index.blade.phpを編集

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事一覧')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<div>
<a href="/articles/create">新規作成</a>
</div>
@foreach ($articles as $article)
<h4>{{$article->title}}</h4>
<p>{{$article->body}}</p>
<a href="/articles/{{$article->id}}">詳細を表示</a>
<a href="/articles/{{$article->id}}/edit">編集する</a>
<form action="/articles/{{$article->id}}" method="post">
{{ csrf_field() }}
<input type="hidden" name="_method" value="delete">
<input type="submit" name="" value="削除する">
</form>
{{-- <a href="/articles/{{$article->id}}">削除する</a> --}}
<hr>
@endforeach
@endsection


詳細ページに削除リンクを貼る

resources/views/articles/show.blade.phpを編集する

{{-- layoutsフォルダのapplication.blade.phpを継承 --}}

@extends('layouts.application')

{{-- @yield('title')にテンプレートごとの値を代入 --}}
@section('title', '記事詳細')

{{-- application.blade.phpの@yield('content')に以下のレイアウトを代入 --}}
@section('content')
<h1>{{$article->title}}</h1>
<p>{{$article->body}}</p>
<br><br>
<a href="/articles/{{$article->id}}/edit">編集する</a>
<form action="/articles/{{$article->id}}" method="post">
{{ csrf_field() }}
<input type="hidden" name="_method" value="delete">
<input type="submit" name="" value="削除する">
</form>
<a href="/articles">一覧に戻る</a>
@endsection


destroyアクションに処理を書く

app/Http/Controllers/ArticlesController.phpを編集する

<?php

public function destroy($id)
{
// idを元にレコードを検索
$article = Article::find($id);
// 削除
$article->delete();
// 一覧にリダイレクト
return redirect('/articles');
}

以上でLaravelでのCRUD処理は全て実装完了です!


注意書き


バリデーションなどをかけていないのは、CRUDをさーっと実装するためです。

Laravel歴は一週間程度なので、アドバイスやツッコミなどありましたら、お手柔らかなコメントお願いします。。


Laravelすごくいい