以下の続き。
フォルダ一覧までは作成できた。
■(1)〜(3)の復習:
・環境構築と設計
・開発のざっくり流れ
①ルーティング設定(web.php)
②コントローラーの作成・記載
③マイグレーションファイルの作成・記載
④マイグレーションの実行
⑤モデルクラスの作成
⑥テストデータの挿入
⑦コントローラーの追記・修正
⑧テンプレートの作成
・ルーティング設定(web.php)の記載方法
Route::get('/folders/{id}/tasks', 'TaskController@index')->name('tasks.index');
→getで/folders/{id}/tasksにリクエストがきたら、TaskControllerのindexメソッドを呼び出す。
これを'tasks.index'と名づける。
・コントローラーの生成コマンド
php artisan make:controller (コントローラーの名前)
・マイグレーションファイルの生成コマンド
php artisan make:migration create_(テーブル名)_table --create=(テーブル名)
→database/migrations ディレクトリに YYYY_MM_DD_hhmmss_create_folders_table.phpが生成される。
・マイグレーションの実行コマンド
php artisan migrate
・モデルクラスの生成コマンド
php artisan make:model (モデル名)
・View関数の使い方
public function index ()
{
$var = 'XXX';
return view('aaa', ['varvar' => $var]);
}
上記のコードのように書けば「resources/views/aaa.blade.php」ビューへ、'varvar'という変数名で$varを渡すことができます。第二引数は"['渡す先での変数名' => 今回渡す変数]"。
・route関数の使い方
@foreach($folders as $folder)
<a href="{{ route('tasks.index', ['id' => $folder->id]) }}" class="list-group-item">
{{ $folder->title }}
</a>
@endforeach
route関数の第一引数はルート名、第二引数は、ルート URL のうち変数になっている部分(ここでは {id})に実際の値を埋める)。
'tasks.index'は以下のルートで、{id}にはループで回しているfolderのidが入る。
Route::get('/folders/{id}/tasks', 'TaskController@index')->name('tasks.index');
ここまでが(1)~(3)の復習。
入門Laravelチュートリアル (4) ToDoアプリのタスク一覧表示機能を作る
フォルダ一覧の次はタスク一覧をつくった。①、②は済みのため、Taskテーブルのマイグレーションファイル作成からスタート。
①ルーティング設定(web.php)
→記載済み。
②コントローラーの作成・記載
→TaskController作成済み
③マイグレーションファイルの作成・記載
④マイグレーションの実行
⑤モデルクラスの作成
⑥テストデータの挿入
⑦コントローラーの追記・修正
⑧テンプレートの作成
③マイグレーションファイルの作成・記載
php artisan make:migration create_tasks_table --create=tasks
上記コマンドで生成されたマイグレーションファイルをテーブル定義に従って修正。
// 外部キーを設定する
$table->foreign('folder_id')->references('id')->on('folders');
外部キー制約について。
上記では、タスクテーブルのフォルダIDカラムにフォルダテーブルのIDカラムへの外部キー制約を設定。
今回、一つのフォルダに複数のタスクが紐づく。
フォルダ1
|
|--- タスク1
|
|--- タスク2
|
|--- タスク3
データの不整合を防ぐために、タスクテーブルのフォルダIDには、勝手に値を入れるのではなく、フォルダテーブルのIDとして存在する値をいれなければいけない。
タスクテーブル
カラム論理名 | カラム物理名 | 型 | 型の意味 |
---|---|---|---|
ID | id | SERIAL | 連番(自動採番) |
フォルダID | folder_id | INTEGER | 数値 |
・・・ |
フォルダーテーブル
カラム論理名 | カラム物理名 | 型 | 型の意味 |
---|---|---|---|
ID | id | SERIAL | 連番(自動採番) |
・・・ |
④マイグレーションの実行
php artisan migrate
⑤モデルクラスの作成
php artisan make:model Task
⑥テストデータの挿入
シーダーでtasksテーブルにデータを挿入。
tinkerでちゃんとテーブルにデータが入ったか、確認。
⑦コントローラーの追記・修正
タスク取得処理を追加。
// 選ばれたフォルダに紐づくタスクを取得する
$tasks = Task::where('folder_id', $current_folder->id)->get();
Laravel が提供するクエリビルダの機能を使用。
SQL を書かなくても PHP 風な記述でデータ操作を表現できる。
SQL は裏側で生成されデータベースに発行。
get メソッドを忘れがちなので気をつける。
return view('tasks/index', [
'folders' => $folders,
'current_folder_id' => $current_folder->id,
'tasks' => $tasks,
]);
コントローラーからtaskの情報をとれるようになったので、テンプレート(ビュー)にtaskの情報を渡すように追記。
⑧テンプレートの作成
コントローラーからtaskの情報を受け取ったので、一覧画面に「resources/views/tasks/index.blade.php」フォルダ一覧だけでなくタスク一覧も表示するように記載を追加。
タスク追加ボタン、タスク一覧が追加されるが、現時点でタスク追加や編集はできないので、href="#"としている。
ここまででフォルダ一覧とタスク一覧の表示はできたが、状態や日付形式を見直しするためにLaravelのモデルに関する機能である「アクセサ」を用いてブラッシュアップ。
⑨Taskモデルにアクセサを追加
・・・ちょっと難しかったが現時点での理解を記載。
タスクテーブル
カラム論理名 | カラム物理名 | 型 | 型の意味 |
---|---|---|---|
ID | id | SERIAL | 連番(自動採番) |
フォルダID | folder_id | INTEGER | 数値 |
タイトル | title | VARCHAR(100) | 100文字までの文字列 |
状態 | status | INTEGER | 数値 |
期限日 | due_date | DATE | 日付 |
作成日 | created_at | TIMESTAMP | 日付と時刻 |
更新日 | updated_at | TIMESTAMP | 日付と時刻 |
アクセサとは:
ModelにgetHogeHogeAttribute()メソッドを定義することで、コントローラーやテンプレートで${{hoge_hoge}}としてDBの情報を加工して簡単に表示することができる。
<<Task.php>>
class Task extends Model
{
/**
* 状態定義
*/
const STATUS = [
1 => [ 'label' => '未着手' ],
2 => [ 'label' => '着手中' ],
3 => [ 'label' => '完了' ],
];
/**
* 状態のラベル
* @return string
*/
public function getStatusLabelAttribute()
{
// 状態値
$status = $this->attributes['status'];
// 定義されていなければ空文字を返す
if (!isset(self::STATUS[$status])) {
return '';
}
return self::STATUS[$status]['label'];
}
}
以下でTasksテーブルのstatusカラムを取得(数値1~3が取れる想定)。
$status = $this->attributes['status'];
取得したstatusの値が数値1~3でない場合、空文字を返す。
// 定義されていなければ空文字を返す
if (!isset(self::STATUS[$status])) {
return '';
}
取得したstatusの値が数値1~3の場合、'未着手'/'着手中'/'完了'を返却する。
return self::STATUS[$status]['label'];
}
Modelにて上記の設定ができたら、コントローラーやテンプレートにて、'未着手'/'着手中'/'完了'を取得できる。
Modelで定義した関数がgetStatusLabelAttribute()だったので、コントローラーやテンプレートで取得する際は、以下のようにする。
<span class="label">{{ $task->status_label }}</span>
これで、状態を数値でなく'未着手'/'着手中'/'完了'で表示できるようになった。
ちなみに、この「self::」とはなんだろうか??「self::」は自分のクラスを表しthisは自分のインスタンスを表す。静的なプロパティにアクセスする際は、「self::」を使用し、動的なプロパティやメソッドにアクセスする際は、thisを使用する。
続いて、状態に応じて色を付ける。
アクセサとBootstrapをうまく活用していてすごいと思った。
上記の通り、Bootstrapでclassに定義することで、色をつけることができる。
/**
* 状態定義
*/
const STATUS = [
1 => [ 'label' => '未着手', 'class' => 'label-danger' ],
2 => [ 'label' => '着手中', 'class' => 'label-info' ],
3 => [ 'label' => '完了', 'class' => '' ],
];
/**
* 状態を文字で表示する
* @return string
*/
public function getStatusLabelAttribute()
{
// 状態値
$status = $this->attributes['status'];
// 定義されていなければ空文字を返す
if (!isset(self::STATUS[$status])) {
return '';
}
return self::STATUS[$status]['label'];
}
/**
* 状態に色を付ける
* @return string
*/
public function getStatusClassAttribute()
{
// 状態値
$status = $this->attributes['status'];
// 定義されていなければ空文字を返す
if (!isset(self::STATUS[$status])) {
return '';
}
return self::STATUS[$status]['class'];
}
STATUS定義にBootstrapを踏まえたclass定義を追加し、ステータスカラムに応じたclassを返すメソッドを追加。
テンプレート側で以下の通り定義することで、色づけすることができる。
<span class="label {{ $task->status_class }}">{{ $task->status_label }}</span>
⑩モデルクラスにおけるリレーション
タスクコントローラーではタスクの一覧を以下のコードで取得した。
$tasks = Tasks::where('folder_id', $current_folder->id)->get();
ここで紹介する機能を使うとこのように書き直すことができる。(めっちゃ便利・・・!)
$tasks = $current_folder->tasks()->get();
上でも記載の通り、今回、一つのフォルダに複数のタスクが紐づく。
これを踏まえて、Folderクラスに以下の記載を加える。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Folder extends Model
{
public function tasks()
{
return $this->hasMany('App\Task');
}
}
実際に、タスクコントローラーの記載を以下のように修正する。
// 選ばれたフォルダに紐づくタスクを取得する
$tasks = Task::where('folder_id', $current_folder->id)->get();
長くなったので、(4)までで一旦、区切る。