初めに
MakeIT AdventCalendarの18日目のyamato3310です。
先輩からlaraverl入門を借りたときに、読み終わったら教えてと言われていたので、またtodoリストを作ることにします。
そしてこのサークル内でぺちぱーが増えてほしいなぁと。ぺちぱートークがしたい
下の画像はlaravelの仕組みです。
laravelのインストール
まずはこのサイトを参考にcomposerをインストールしてください。
ComposerのインストールからLaravelプロジェクトの作成及び実行まで
composer create-project laravel/laravel --prefer-dist todo
これでlaravelのインストールができます。
試しにプロジェクトを実行してみましょう。
php artisan serve
後はhttp://127.0.0.1:8000/にアクセスしてlaravelと書かれたページが表示されれば成功です。
todoリストの制作
はい、todoリストを作ります。
laravelは基本web.phpでルーティング処理を書きそこで~~Controller@メソッドという形で、このアクセスが来たらこの処理をするというふうに書き、呼び出されたcontrollerクラスでデータをゴニョゴニョしてviewにデータを渡し、そのviewを表示させています(細かくは違うと思いますが大体こんな感じです)
今回はデータベース周りをEloquentというのを使います。
Eloquentを知らない場合は以下の記事を参考にしてください。
Eloquentについて
Modelクラスを制作
php artisan make:model Todo
これでApp/Todo.phpが作られます。
Eloquentでは、レコードはモデルのインスタンスとして扱われます。カラム名todoをデータベースから取ってくると、それはtodoモデルのインスタンスとして扱います。(分かりづらくてすいません。。。)
また下で出てくるのでそのときにまた説明します。。。
内容は以下の通りに書き換えてください。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Todo extends Model
{
protected $guarded = ['id'];
protected $table = 'todo';
public static $rules = [
'title' => 'required',
'content' => 'required',
];
public function scopeFlg ($query, $num) {
return $query->where ('flg', $num);
}
}
protected $guarded = ['id'];とは後でやりますが、データを保存するときにidは入りませんよという意味です。今回のidはAUTO_INCREMENTがついているので、データを保存するときに必要がないからです。
protected $table = 'todo';は名前の通りテーブル名です。laravelでは、テーブル名は複数形でModelクラスは単数形というルールが有ります。ここで名前をつけない場合、このモデルを使うときに勝手に複数形(今回はtodos)となってしまいそんなテーブルは存在しないと怒られてしまいます。自分はこれに気づかずに結構な時間を溶かしました。。。
public static $rulesはバリデーションのルールを連想配列で決めておくところです。今回はrequiredをつけていますがこれは入力必須という意味です。他にもルールはありますが今回は省略します。
public function scopeFlg ($query, $num) {...}はローカルスコープというものです。ローカルスコープとは明示的に呼び出して条件を絞り込むものです。これも使うときに説明します。
これでModelクラスは終了です次からはControllerクラスを作っていきます。
controllerクラスの制作
php artisan make:controller TodoController
これでapp/Http/ControllerにTodoController.phpができます
このTodoController.phpを以下のように書き換えてください
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Todo;
class TodoController extends Controller
{
public function index () {
$runningItems = Todo::flg (1)->get ();
$doneItems = Todo::flg (0)->get ();
return view ('todo', [
'runningItems' => $runningItems,
'doneItems' => $doneItems,
]);
}
public function create (Request $request) {
$this->validate ($request, todo::$rules);
$todo = new Todo;
$form = $request->all ();
unset ($form['_token']);
$form['flg'] = 1;
$todo->fill ($form)->save ();
return redirect ('/todo');
}
public function update (Request $request) {
$todo = Todo::find ($request->id);
$todo->flg = 0;
$todo->save ();
return redirect ('/todo');
}
public function delete (Request $request) {
$todo = Todo::find ($request->id);
$todo->delete ();
return redirect ('/todo');
}
}
ここでは上記でも書いたようにデータをゴニョゴニョしている部分です。
各メソッドの引数に(Request $request)このような記述がありますがlaravelではこのように書くだけで今回でいうと、Requestのインスタンスが用意されます。
indexメソッドを例に説明していきます。
$runningItems = Todo::flg (1)->get ();はい、早速ローカルスコープを使っています。
Todo::flg (1)の部分です。待ってくださいTodoクラスでflgメソッドなんて定義していませんよね??
TodoクラスではscopeFlgメソッドは定義しています。ローカルスコープは特殊で定義するときは、scope~~と定義して呼び出すときはscopeを省略して呼ぶからです。あとscopeFlgでは引数が($query, $num)このように2つあったのに呼び出すときは引数が一つだけですよね?これはローカルスコープを呼び出すときは$queryを省略するからです。なので今回は$numに1が入りflg = 1をのデータを->get ();で取って来ています。
取ってきた値は$runningItemsに格納していますがこれは、上でも言ったようにModelクラスのインスタンスです。
return view ('todo', [...])はviewを返しています。今回はtodoですがこれはresources/views/todo.blade.phpのことを指しています。
resources/views/は省略します。第二引数に、viewに渡すデータを書きます。keyに変数名、valueに格納する値を書きます。todo.blade.phpとありますがこれは下で説明します。
$this->validateとありますが名前の通りvalidationをしてくれます。第一引数にRequestクラスのインスタンス、第二引数にModelクラスで定義した$rulesを入れます。laravelではvalidation時に問題が発生するとその場で元のページへ戻ります。
$todo = Todo::find ($request->id);のTodo::find ($request->id)とはidテーブルから指定したデータを取ってくるという意味です。Eloquentでは、テーブルのプライマーキーはidという整数値のフィールドという前提でfindを実行しています。
$todo->fill ($form)->save ();は簡単に言うと、データベースへの保存です。これの前に$todo = new Todo;とやっていますよね、ElquentではModelクラスのインスタンスに保存するデータを格納して->save ()とするだけでデータベースへ保存することができます。データの格納の方法ですが、$todo->title = $request['title']という形で一つずつ格納することもできますが、->fill ()とすることでまとめて格納することができます。
unset ($form['_token']);はフォームから送られてきた_tokenを削除しています。後で出てきますがフォームの中に{{csrf_field ()}}があり、csrf対策用のトークンが送られてきますがデータベースへ保存するときにいらないので、ここで削除しています。
これでControllerクラスの説明は終わります。次はデータベースへ接続するための設定を変えます。
.env修正
ここでは、.envファイルを修正していきます。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todolist
DB_USERNAME=root
DB_PASSWORD=
.envファイルの9行目以降です。ここにデータベースの設定を書いていきます。
マイグレーションの設定
マイグレーションとはデータベースのバージョン管理機能です。ざっくりいうとコマンド一つでテーブルを作ってくれるものです。
マイグレーションファイルは以下のコマンドで生成されます。
php artisan make:migration create_todo_table
これでdatabase/migrations/制作時間_create_todo_table.phpが作られます。内容は以下のとおりに変更してください。
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTodoTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('todo', function (Blueprint $table) {
$table->increments ('id');
$table->string ('title');
$table->string ('content');
$table->string ('flg');
$table->timestamps ();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('todo');
}
}
ここでは、$table->~~という感じに~~にデータの型と()にテーブル名を書きます
マイグレーションを実行するにはphp artisan migrateで出来ます。
viewの制作
最後にviewの制作をしていきます。
resources/viewsにtodo.blade.phpというファイルを作ってください。
bladeとは、laravelが独自に作ったテンプレートエンジンです。
内容を以下のように変更してください。
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<link rel='stylesheet' href="{{asset ('/css/todo.css')}}">
</head>
<body>
<ul class='ul'>
<li>これからやること</li>
@if (isset ($runningItems))
@foreach ($runningItems as $runningItem)
<li class='todo'>{{htmlspecialchars ($runningItem->title) ." " .htmlspecialchars ($runningItem->content)}}</li>
<li>
<form method='POST' action="/todo/update">
{{csrf_field ()}}
<input type='hidden' value="{{$runningItem->id}}" name='id'>
<input type='hidden' value="{{$runningItem->flg}}" name='flg'>
<input type='submit' value='終了' class='todo_button'>
</form>
</li>
@endforeach
@endif
</ul>
<ul class='ul'>
<li>もうやったこと</li>
@if (isset($doneItems))
@foreach ($doneItems as $doneItem)
<li class='todo'>{{htmlspecialchars ($doneItem->title) ." " .htmlspecialchars ($doneItem->content)}}</li>
<li>
<form method='POST' action="todo/delete">
{{csrf_field ()}}
<input type='hidden' value="{{$doneItem->id}}" name='id'>
<input type='hidden' value="{{$doneItem->flg}}" name='flg'>
<input type='submit' value='削除' class='todo_button'>
</form>
</li>
@endforeach
@endif
</ul>
<form method="POST" class='form' action="/todo" action="todo/create">
{{csrf_field ()}}
<input type="text" placeholder="タイトルを入力してね" name="title" class='title'>
<textarea placeholder="内容を入力してね" name='content' class='content'></textarea>
<input type="submit" value="追加" class='todo_button'>
</form>
</body>
</html>
このファイル内でif文使うときは@ifとはじめに@をつけてはじめ、最後に@endifというふうに閉じます。
Controllerクラスから呼ぶときに第二引数に連想配列で[変数名 => 値]というふうに書きましたよね?
ここでは{{ }}で囲うことで値を埋め込むことが出来ます。基本的に埋め込まれた値はエスケープ処理がされます
{{csrf_field ()}}は上でも書いたようにcsrf対策用のトークンを生成するものです。
bladeには他にも様々な便利な機能がありますが、自分がうまく使えていないので省略させていただきます。。。
ルーティング
最後にルーティング処理を書いていきます。
routes/web.phpを以下のように変更してください
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/todo', 'TodoController@index');
Route::post('/todo', 'TodoController@create');
Route::post('/todo/update', 'TodoController@update');
Route::post('/todo/delete', 'TodoController@delete');
基本的にRoute::リクエスト名 (url, 呼び出すコントローラー@メッソド)と書きます
最後に
これでphp artisan serveを実行してhttp://127.0.0.1:8000/todoにアクセスしてください。
これでtodoリストが表示されれば成功です
ちなみにcssは前回の記事の下の方にあるので使ってみてください
下に行くに連れて説明が雑になっている気がするがそれはきのうせいです
この記事はこのコードを書いてしばらくしてから書いたものなのでどこかがまるまる抜けているかもしれません、そうならないようにしていますがもし何かあればコメントしていただければ。。。
次のitti1021さんが自分よりとっっっっっっても良い記事を書いてくれます。お楽しみに!!
