Laravel5.6入門 基本CRUD操作を体で覚える
はじめに
プログラミングは「習うより慣れろ」ということで、アプリケーションの基本のCRUDをLaravelでやってみた。
※ 書いているのは生意気にもLaravel歴一週間程度の初心者です。
MVCアーキテクチャのフレームワークだと作業手順としては、ものすごくざっくりだと以下のような流れになるんじゃないかと思う。
- モデル作成
- マイグレーション作成
- コントローラー作成
- ルーティング作成
- ビュー作成
対象となる読者
- 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.php
のrun(){}
内に、$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
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.php
の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::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.php
のshow
アクションを編集します。
<?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/articles
にcreate.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
のコントローラーを修正する
新規作成に関連するアクションはcreate
とstore
のアクションなので、コントローラーもその二つのアクションを編集する。
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すごくいい