miyupaca log

Laravel-Todoアプリに一週間機能追加チャレンジ

2020/09/13

こんにちは、miyupacaです٩( ‘ω’ )و

最近LaravelでTodoアプリを作ったのですが、学習のために一週間機能追加チャレンジというのを一人で勝手にやっていました。
文字通り毎日何かしらの機能追加をやっていくという試みです。

元のアプリを作った学習ログはこちらになります。
2020-09-05 yps学習記録その6

最初はメール認証ユーザ登録と、タスクの基本操作(登録、読み取り、更新、削除)ができるシンプルなものでした。
そこから追加したのは以下の機能です。

  • day1:タスクに優先度を追加、タスクのソート機能追加
  • day2:タスクとユーザをIDで紐づけ、作成ユーザを表示
  • day3:ユーザ情報の表示と名前変更機能
  • day4:締切当日&過ぎたタスクを色で目立たせる、パスワード変更機能
  • day5:メール認証でメアド変更機能
  • day6:タスクのdescriptionの表示調整(文字数制限と改行)、編集削除を自分のタスクだけに制限
  • day7:ブログにまとめる(ここまで含めてチャレンジだから。。。)

(自分に強制力を働かせるために)毎日動画付きでツイートしてたので、もしよかったらどうぞ!(以下のツイート参照していただくとつながっています)

それでは、ざっくりと振り返ろうと思います。
特に後半なのですが、参考記事のみ貼り付けて終わってるような項目もありますがご容赦ください。


day1:タスクに優先度を追加、タスクのソート機能追加

タスクに優先度を追加

カラムの追加なのでマイグレーションで対応。
これを

$ php artisan make:migration add_priority_to_tasks_table --table=tasks

こうして

public function up()
{
    Schema::table('tasks', function (Blueprint $table) {
        //
        $table->integer('priority');
    });
}

こうじゃ!

$ php artisan migrate

ビューに表示するのは星にしたかったので

<td>
 @if( ($task->priority) == 0 ) -
    @elseif(($task->priority)== 1 ) ★ 
    @elseif(($task->priority)== 2 ) ★★
    @elseif(($task->priority)== 3 ) ★★★
  @endif
</td>

タスク作成フォームのビューはこんな感じ。

<div class="form-group">
  <label for="priority-field">Priority</label>
  <select name="priority" id="priority-field">
    <option value="0" selected>-</option>
    <option value="1"></option>
    <option value="2">★★</option>
    <option value="3">★★★</option>
  </select>
</div>

更新フォームもほぼ同じですが前回値を見せるために

<option value="1" @if(old('priority', $task->priority ) == 1 ) selected  @endif></option>

こんな感じで各選択肢のselectedを制御してました。

タスクのソート機能

初期はid順で、あとで他の要素で並び替えられるようにした。

public function index(Request $request)
{
    $sort = $request->sort;
    if (is_null($sort)) {
        $sort = 'id';
    }
    $tasks = Task::orderBy($sort,'desc')->paginate();
    $param = ['tasks' => $tasks, 'sort' => $sort];
    return view('tasks.index', compact('tasks'));
}

降順だけですがこんな感じで書けばok。

並び替え機能のリンクはビューに。

<tr>
  <th class="text-center"><a href="/tasks?sort=id">No.</a></th>
  <th>Subject</th>
  <th>Description</th>
  <th><a href="/tasks?sort=due_date">Due Date</a></th>
  <th><a href="/tasks?sort=completed">Completed</a></th>
  <th class="text-right">OPTIONS</th>
</tr>

tasks?sort=カラム名で並び替え可能に。

参考:https://note.com/kawa1228/n/n42e823ea6d60


day2:タスクとユーザをIDで紐づけ、作成ユーザを表示

テーブル定義を変更するのでまたマイグレーション。

$ php artisan make:migration add_user_id_to_tasks_table --table=tasks

user_idカラムを追加して、ユーザのidと紐づける。

public function up()
{
  Schema::table('tasks', function (Blueprint $table) {
  $table->bigInteger('user_id')->unsigned();
      
  $table->foreign('user_id')
        ->references('id')
          ->on('users')
          ->onDelete('cascade');
  });
}

マイグレートしようとしたら元のデータが入っているエラーが出てしまったので、refreshしてから実行。

$ php artisan migrate:refresh
$ php artisan migrate

モデルに紐付け設定。
Taskモデル

public function user()
	{
		return $this->belongsTo('App\User');
	}

Userモデル

public function task() {
	return $this->hasMany("App\Task", 'user_id', 'id');
}

一人のユーザがたくさんタスクを持てる設計なのでこんな感じになります。

参考: https://note.com/laravelstudy/n/n886d46e180bd

あとはユーザを紐づけるためにタスク作成時にログインしてるユーザを引っ張ってくる。 Taskコントローラにまず以下を追加。

use Illuminate\Support\Facades\Auth;

そして、createメソッドの

$inputs = $request->all();
Task::create($inputs);

の部分を以下のようにに置き換えた。

$inputs = $request->all();
$task = new Task();
$task->subject = $inputs["subject"];
$task->description = $inputs["description"];
$task->due_date = $inputs["due_date"];
$task->priority = $inputs["priority"];
$task->user_id = Auth::id();
$task->save();

$task->user_id = Auth::id();の部分が新規部分。
冗長なのでもっと良い書き方もある気が。。。とりあえずできた。

あとはビューに名前を表示させるように追記。

{{$task->user->name}}

シンプルだけどこの記法がすぐにわからずにちょっと悩んだ。

参考: https://qiita.com/yukibe/items/b7186f05d1c266076a35


day3:ユーザ情報の表示と名前変更機能

ユーザ登録機能はあったが自分の情報を見たり編集したりする場所がなかったので作成。

  • Userコントローラがなかったので作成。
  • index,edit,updateメソッドを作成。
  • ルートに上記を追加。
  • indexとedit用のビューを作成。

終わり!

参考:
https://fippiy.hatenablog.jp/entry/2019/04/20/142040
https://qiita.com/syokichi09/items/5a67c000eeb55e690afd


day4:締切当日&過ぎたタスクを色で目立たせる、パスワード変更機能

締切当日&過ぎたタスクを色で目立たせる

日付チェックはビュー内でif文で行った。

<td>
  @if( ($task->due_date) < date('Y-m-d') )
  <p class="text-danger">{{$task->due_date}}</p>
  @elseif( ($task->due_date) == date('Y-m-d') )
  <p class="text-success">{{$task->due_date}}</p>
  @else
  {{$task->due_date}}
  @endif
</td>

ごちゃごちゃするのでコントローラなどでうまく制御できるとより良さそう。
(後からの気づき)

パスワード変更機能

こちらの記事を大いに参考にした。
http://ryota01.com/archives/22
追加でやったのはコントローラやビューの調整くらいだった記憶。


day5:メール認証でメアド変更機能

こちらの記事を大いに参考にした。
https://yaba-blog.com/laravel-email-chenge/#toc7
追加でやったのはコントローラやビューの調整くらいだった記憶。


day6:タスクのdescriptionの表示調整(文字数制限と改行)、編集削除を自分のタスクだけに制限

タスクのdescriptionの表示調整

文字数制限は以下でできる。

{!! Str::limit($task->description, 30) !!}

改行の反映は以下でできる。

{!! nl2br(e($task->description)) !!}

編集削除を自分のタスクだけに制限

今回はTaskの操作に対して制限を付けたかった。 特定のモデルに対する認可の操作にはポリシーというものが良さそうらしい。

公式ドキュメントのポリシー作成のところを参照。 https://readouble.com/laravel/7.x/ja/authorization.html

ポリシーを作成

$ php artisan make:policy PostPolicy --model=Post

updateとdeleteに追記

public function update(User $user, Task $task)
{
    //
    return $user->id == $task->user_id;
}

public function delete(User $user, Task $task)
{
    //
    return $user->id == $task->user_id;
}

AuthServiceProviderへの追記

protected $policies = [
    'App\Task' => 'App\Policies\TaskPolicy',
];

あとはTaskコントローラにポリシーから帰ってきた結果に応じた操作を書く。 リダイレクトしてエラーメッセージを出してしたかったのだが、普通だと制限時に404ページに飛ばされる。

どうすればいいかなと調べていたら以下の記事の「認可レスポンスの改善」が大変参考になった。 https://qiita.com/tomoeine/items/f92de7d035e0fe8e7362
falseの時にリダレクトとエラーメッセージを出すように記述することで実装できた。

以下の記事もポリシー(とゲート)の理解に役立ったのでおすすめ。 https://reffect.co.jp/laravel/laravel-gate-policy-understand


気づきなど

phpはechoなら知ってるけど?レベルでLaravelに向き合った(!)のでなかなかしんどかったですがとにかくぐぐりまくりました。
機能は充実してきましたが今やりたいのはリファクタリングです。ソースコードがとにかくごちゃごちゃ。
設計などもなく肉付けする作業の進め方だったので想定内ではあるのですが気になってきました…!
あとはまだできそうな機能追加は色々あるので、アプリを育てていきたい。

引き続きLaravelのお勉強頑張ります( ´ ▽ ` )


miyupacaの学習記録ブログです。