Laravel初心者の私がTODOアプリを作成した際の手順をまとめてみました。
*ベストなやり方ではないかもしれないのでご了承ください。
このようなTODOアプリを作成していきます。CSSの適用の仕方も書いているので、デザインはご自身でカスタマイズしてみてください。
前提
・MAMP環境を利用・mysqlのPathは設定済み
・データベースは作成済
目次
1. プロジェクトフォルダの作成2. データベースの接続先の設定
3. マイグレーションファイルの作成
4. マイグレーションファイルの編集
5. マイグレーションの実行
6. モデルの作成
7. ルーティングファイルの編集
8. コントローラーの作成
9. bladeファイルの作成
10. CSSの調整
1. プロジェクトフォルダの作成
まず、下記コマンドでプロジェクトフォルダを作成します。composer create-project "laravel/laravel=8.*" todoapp --prefer-dist
todoapp
というところがプロジェクトフォルダ名です。
2. データベースの接続先の設定
プロジェクト直下の.env
ファイルを開き、データベースの接続先を設定します。
DB_CONNECTION=mysql
DB_UNIX_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=(データベース名)
DB_USERNAME=root
DB_PASSWORD=(パスワード)
DB_UNIX_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
に関しては、接続できなかった場合に試してみてください。
次にconfig/database.php
を変更します。
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_UNIX_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
DB_UNIX_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
を追加した場合、'unix_socket' => env('DB_SOCKET', ''),
を'unix_socket' => env('DB_UNIX_SOCKET', ''),
に書き換えます。
3. マイグレーションファイルの作成
次にテーブルを作成するためのマイグレーションファイルを作成します。php artisan make:migration create_todos_table
database/migrations
の中にxxxx_xx_xx_xxxxxx_create_todos_table
というマイグレーション ファイルが作成されます。
4. マイグレーションファイルの編集
下記のようにマイグレーションファイルを編集します。<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTodosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->id()->nullable(false);
$table->string('content', 191)->nullable(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('todos');
}
}
この部分でテーブルの構造を定義しています。
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->id()->nullable(false);
$table->string('content', 191)->nullable(false);
$table->timestamps();
});
}
nullable(false)
→ 値が入っていることが必須という意味。
string('content', 191)
→ string('カラム名', 長さ)
という意味。
timestamps()
→ created_at
とupdated_at
のカラムの作成に使われる。
5. マイグレーションの実行
下記コマンドでマイグレーションを実行します。php artisan migrate
下記コマンドでテーブルを確認すると、先ほどマイグレーションファイルで定義した通りになっています。
mysql> SHOW COLUMNS FROM todos;
確認してみてください。
6. モデルの作成
Laravelには、Eloquent(エロクアント)というORMが搭載されています。Laravelではクラス(モデル)を用意して操作すると、対応するデータベースを自動的に操作することができます。
モデルを作成することで、後ほど説明するTodoController.php
で簡単にデータベースの操作を行うことができるようになります。
php artisan make:model Todo
これでモデルが作成できます。テーブル名は複数形、モデル名は単数形という決まりがあります。今回はtodos
というテーブルだったので、単数形のTodo
というモデルを作成しました。これで、モデルとテーブルが紐づきます。
プロジェクトフォルダのapp>Models
フォルダの中を確認してみましょう。そこにTodo.php
というファイルが作成されています。
今回はTodo.php
の中身は特に変更しなくても大丈夫ですが、モデルは、
①データ構造とそれを操作する全て(処理、検証、保存など)
②データ層へのアクセス
などに使うファイルとのことです。
7. ルーティングファイルの編集
次にルーティングファイルroutes/web.php
を編集します。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TodoController;
Route::get('/', [TodoController::class, 'index']);
Route::post('/create', [TodoController::class, 'create']);
Route::post('/update', [TodoController::class, 'update'])->name('todo.update');
Route::post('/delete', [TodoController::class, 'delete'])->name('todo.delete');
どこにアクセスしたら、どのアクションが実行されるのかを定義していきます。
今回は下記を定義します。
・トップページ(/)
にアクセス → コントローラーに書かれたindexアクション
を実行。データベースの中身を取得し、ページに表示させます。
・レコード作成(/create)
にアクセス → コントローラーに書かれたcreateアクション
を実行。テーブルに新しいレコードを作成し、トップページにリダイレクトさせます。
・レコード更新(/update)
にアクセス → コントローラーに書かれたupdateアクション
を実行。レコードの内容を更新し、トップページにリダイレクトさせます。
・レコード削除(/delete)
にアクセス → コントローラーに書かれたdeleteアクション
を実行。レコードを物理削除し、トップページにリダイレクトさせます。
また、use App\Http\Controllers\TodoController;
の部分で、参照するコントローラーを指定しています。
ちなみに、ルートには名前を付けることができるのですが、update
とdelete
にはそれぞれ下記のように名前を付けています。
->name('todo.update')
->name('todo.delete')
8. コントローラーの作成
下記コマンドを実行し、todoコントローラーを作成します。
php artisan make:controller TodoController
app/Http/Controllers/TodoController.php
が作成されました。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Todo;
class TodoController extends Controller
{
public function index()
{
$todos = Todo::all();
return view('index', ['todos' => $todos]);
}
public function create(Request $request)
{
$request->validate([
'new_content' => 'required|min:3|max:20'
], [
'new_content.required' => '必須項目です!',
'new_content.min' => ':min 文字以上入力してください。',
'new_content.max' => ':max 文字以下で入力しください。'
]);
$post = new Todo();
$post->content = $request->new_content;
$post->save();
return redirect('/');
}
public function update(Request $request)
{
$request->validate([
'content' => 'required|min:3|max:20'
], [
'content.required' => '必須項目です!',
'content.min' => ':min 文字以上入力してください。',
'content.max' => ':max 文字以下で入力しください。'
]);
$form = $request->all();
unset($form['_token']);
$update = Todo::find($request->id);
$update->content = $request->content;
$update->save();
return redirect('/');
}
public function delete(Request $request)
{
$delete = Todo::find($request->id);
$delete->delete();
return redirect('/');
}
}
●indexアクション
$todos = Todo::all();
の部分でtodoテーブルの全ての情報を取得し、$todos
に代入しています。
return view('index', ['todos' => $todos]);
の部分はindex.blade.phpを表示するという意味で、先ほど代入したテーブルの中身$todos
をindex.blade.phpで使うために、todos
にもう一度代入しています。
$todos
のまま送れるのでは?と思いましたが、bladeファイルで使うためにはtodos
に代入する必要があるようです。
●createアクション
あとで説明するindex.blade.php
のインプットフォームから送られてきた値は、$request
に代入されています。また、$request->validate
ではバリデーションを定義することができます。
'new_content' => 'required|min:3|max:20'
この部分の'new_content'
はindex.blade.php
のインプットフォームのname属性
です。
'required|min:3|max:20'
は'必須項目|ミニマム3文字|マックス20文字'
というバリデーションになります。
下記に関しては、
$post = new Todo();
$post->content = $request->new_content;
$post->save();
return redirect('/');
①モデルtodo.php
からインスタンスを生成。
②contentカラムにnew_content
の中身を代入。
③その情報をtodosテーブルに保存。
④(/)
にリダイレクト。
という流れになっています。
●updateアクション
$form = $request->all();
はリクエストの全データを取得して、$form
に代入するという意味です。インプットフォームでは文字しか入力できませんが、実際は色々な情報が送られています。変数の中身を確認するには、dd($form);
をソースコードに追加して、ページにアクセスしてみてください。
また、unset($form['_token']);
でフォームから送られてきた_tokenを削除しています。index.blade.php
からcsrf対策用のトークンが送られて来るのですが、データベースに保存するときに不要なので、ここで削除しています。
下記に関しては、createアクションとほぼ同じですが、
$update = Todo::find($request->id);
$update->content = $request->content;
$update->save();
return redirect('/');
①モデルtodo.php
を利用して、todosテーブルから$request
のIDに一致するものを取得。
②contentカラムにcontent
の中身を代入。
③その情報をtodosテーブルに保存。
④(/)
にリダイレクト。
という流れになっています。
●deleteアクション
レコードを削除するためのアクションですが、
$delete = Todo::find($request->id);
$delete->delete();
①モデルtodo.php
を利用して、todosテーブルから$request
のIDに一致するものを取得。
②IDが一致するレコードを削除。
③(/)
にリダイレクト。
という流れになっています。
ーーーーーーーーーーーーーーーーーーーーーー
ちなみに、コントローラーで上記のデータベース操作の構文を使うためには、use App\Models\Todo;
を記述する必要があります。
9. bladeファイルの作成
resources/views/
の直下にindex.blade.php
を作成します。これはWebページを作成するときのindex.html
のようなものです。
<!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">
<link href="{{ asset('css/style.css') }}" rel="stylesheet">
<title>Document</title>
</head>
<body>
<div class="container">
<h1>TODOアプリ</h1>
@error('content')
<div class="error">{{ $message }}</div>
@enderror
@error('new_content')
<div class="error">{{ $message }}</div>
@enderror
<form action="create" method="post" class="addForm">
@csrf
{{-- <label for="content">TODO</label> --}}
<input type="text" id="content" name="new_content" class="addInput" value = "{{ old('new_content') }}">
<input type="submit" value="追加" class="addButton">
</form>
<table>
<tr class="tableHeader">
<th class="headerCreateDate">作成日</th>
<th class="headerTaskName">タスク名</th>
<th class="headerUpdate">更新</th>
<th class="headerDelete">削除</th>
</tr>
@foreach($todos as $todo)
<tr>
<td class="itemCreateDate">
{{ $todo->updated_at }}
</td>
<form action="{{ route('todo.update', ['id' => $todo->id]) }}" method="post">
@csrf
<td>
<input type="text" name="content" value="{{ $todo->content }}" class="updateInput">
</td>
<td>
<input type="submit" value="追加" class="updateButton">
</td>
</form>
<td>
<form action="{{ route('todo.delete', ['id' => $todo->id]) }}" method="post">
@csrf
<input type="submit" value="削除" class="deleteButton">
</form>
</td>
</tr>
@endforeach
</table>
</div>
</body>
</html>
上から順番に見ていきます。
@error('content')
<div class="error">{{ $message }}</div>
@enderror
content
に関するエラーがある場合、エラーメッセージを表示するという記述になります。エスケープ処理のため、Blade上では、変数を{{ }}
で囲って記述します。
<form action="create" method="post" class="addForm">
@csrf
<input type="text" id="content" name="new_content" class="addInput" value = "{{ old('new_content') }}">
<input type="submit" value="追加" class="addButton">
</form>
<form action="create" method="post" class="addForm">
この部分で、フォームを送信したら、ルーティングファイル(web.php)
のcreateにアクセスし、コントローラー(TodoController.php)
のcreateアクションが実行されることになります。
また、ここでインプットフォームに入力された値は、name="new_content"
などの情報と一緒に送信され、$request
に代入されている状態となります。
@foreach($todos as $todo)
@endforeach
この記述は$todos
の中身を一つ一つ、$todo
に入れて繰り返すという意味となります。
<tr>
<td class="itemCreateDate">
{{ $todo->updated_at }}
</td>
<form action="{{ route('todo.update', ['id' => $todo->id]) }}" method="post">
@csrf
<td>
<input type="text" name="content" value="{{ $todo->content }}" class="updateInput">
</td>
<td>
<input type="submit" value="追加" class="updateButton">
</td>
</form>
<td>
<form action="{{ route('todo.delete', ['id' => $todo->id]) }}" method="post">
@csrf
<input type="submit" value="削除" class="deleteButton">
</form>
</td>
</tr>
{{ $todo->updated_at }}
は先ほどforeach
で$todo
に代入されたレコードの中身のupdated_atカラム
の値という意味です。この記述でレコードの作成日が表示されます。
@csrf
はCSRF(クロスサイト・リクエスト・フォージェリ)対策のための記述です。Laravelでは、@csrf
と記述することでCSRF対策を行うことができます。また、これがないとエラーになってしまうので、インプットフォームを使う際は必ず記入しましょう。
<form action="{{ route('todo.update', ['id' => $todo->id]) }}" method="post">
は、route('todo.update')
の部分で、ルーティングで命名したtodo.update
にアクセスしています。
また、id
に$todo
に代入されたレコードの中身のidカラムの値が代入され、これがルーティングを経由して、コントローラーのupdateアクション
に送られます。
TodoController.php
のこの部分です。
public function update(Request $request)
{
$request->validate([
'content' => 'required|min:3|max:20'
], [
'content.required' => '必須項目です!',
'content.min' => ':min 文字以上入力してください。',
'content.max' => ':max 文字以下で入力しください。'
]);
$form = $request->all();
unset($form['_token']);
$update = Todo::find($request->id);
$update->content = $request->content;
$update->save();
return redirect('/');
}
{{ $todo->content }}
の部分は{{ $todo->updated_at }}
を表示したときと同じ処理で、インプットフォームの中に既存のレコードのcontent
を表示しています。
その下の削除の処理は、ほとんど同じ流れなので割愛します。
10. CSSの調整
ここまででTODOアプリの処理は一応完成したので、次にデザインを整えるため、CSSを適用していきます。
CSSファイルは、public/css
の直下に配置します。また、今回はファイル名をstyle.css
にしているので、これを利用するためにはindex.blade.php
に下記を追加します。
<link href="{{ asset('css/style.css') }}" rel="stylesheet">
私が作成したCSSファイルは下記ですがもっと良い感じにカスタマイズしてみてください。
/* 共通 */
body {
background-color: purple;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 60%;
background-color: white;
padding: 40px;
border-radius: 10px;
}
.error {
margin-bottom: 15px;
background-color: darkgrey;
width: 30%;
text-align: center;
}
/* 追加フォーム */
.addForm {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
}
.addInput {
width: 80%;
height: 35px;
}
.addButton {
width: 10%;
color: blueviolet;
background-color: white;
border-color: blueviolet;
border-radius: 5px;
}
/* 更新削除フォーム */
table {
width: 100%;
}
th {
text-align: center;
}
td {
text-align: center;
}
.itemCreateDate {
width: 30%;
}
.updateInput {
height: 25px;
width: 80%;
}
.updateButton {
color: chocolate;
background-color: white;
border-color: chocolate;
border-radius: 5px;
border-style: solid;
height: 40px;
width: 70%;
margin-right: auto;
}
.deleteButton {
color: rgb(146, 252, 211);
background-color: white;
border-color: rgb(146, 252, 211);
border-radius: 5px;
border-style: solid;
height: 40px;
width: 70%;
}
これでTODOアプリが完成すると思います。
誰かの参考になれば幸いです。