【Laravel / Git】LivewireでTodoリストを実装　~ひとりチーム開発やってみた~

##やりたいこと
今回のテーマは、以下の2つです。

* LaravelのLivewireの使い方を、CRUD機能を持ったTodoリストを実装しながら解説する
* Todoリストの実装を、チーム開発を想定したGit flowの流れに沿ってソースコード管理する 

Gitの基本的な使い方やチーム開発の運用について学んだので、コミットしてプッシュしてプルリクエストを作成して…というような手順を実践してみたいなと思っていました。

せっかくならGitの練習のためだけのサンプルコードで行うより、実際に何か開発しながらチーム開発を想定してソースコード管理をやってみようということで、Todoリストの実装をGit flowに沿って管理してみます。

##全体の流れ
###Todoリスト作成の手順
1. Laravelの新規プロジェクト作成 
2. Livewireを使う準備
3. CREATE機能（新規作成）の実装
4. READ機能（一覧表示）の実装
5. UPDATE機能（更新）の実装
6. DELETE機能（削除）の実装 

これらの各機能を実装する度に、下記「Gitでのチーム開発の手順」を繰り返し、ソースコード管理を行なっていきます。

###Gitでのチーム開発の手順
1. ローカルリポジトリでdevelop（開発）ブランチに入る
2. リモートリポジトリのdevelopブランチをローカルのdevelopブランチにプルして、ローカルのdevelopブランチを最新の状態にする。
3. ローカルでdevelopブランチからfeature（機能）ブランチを作り、そこで開発する。
4. 変更点をローカルでcommitする。
5. 作業が終わったら、ローカルのdevelopブランチを再度最新の状態にして、featureブランチに developブランチを取り込む。（rebase or merge）
6. ローカルのfeatureブランチの内容を、リモートリポジトリの同名のブランチへpushする。　
7. リモートのfeatureブランチからリモートのdevelopブランチへ、プルリクエストを発行する。
8. コードレビューをしてもらう。
9. コードレビューが通れば、レビュアーがリモートのdevelopブランチへ featureブランチをmergeする。
10. リモートのdevelopブランチをローカルのdevelopブランチへ取り込んで、 ローカルのdevelopブランチを最新の状態にする。

##1. Laravelの新規プロジェクト作成
###【開発】 新規プロジェクト作成
まずは以下のコマンドで新規プロジェクトを作成し、プロジェクトディレクトリに移動します。
Livewireを使うために、composerを使ってLivewireをインストールします。

```
$ laravel new livewire_todo
$ cd livewire_todo

Livewireをインストール
$ composer require livewire/livewire

現在のディレクトリをVScodeで開く
$ code . 　　　
```
これで、`$ php artisan serve　`とすれば、localhost:8000でlaravelのwelcomeページを表示できるようになっています。

###【Git】　バージョン管理を開始
Gitでの管理を始めます。

通常はプロジェクトに途中から参加することが多いかと思うので、その場合はリモートリポジトリの開発用ブランチ（develop）をローカルにクローンするところから始めることになります。

ですが今回は新しいプロジェクトのためGitHubにリモートリポジトリは無いので、あらかじめGitHubでリモートリポジトリを作成しておきます。


####ローカルリポジトリ作成
GitHubで作成したリモートリポジトリの`Code　>　Clone or download`より、リポジトリのURLをコピーしておきます。

```
//ローカルでのGit管理開始・コミット作成
$ git init
$ git add .
$ git commit

//リモートリポジトリとローカルリポジトリを紐づけ、originというショートカット名で登録
$ git remote add origin リモートリポジトリのURL
```
####SSHで接続する場合
pushする際、GitHubのユーザー名とパーソナルアクセストークンでの認証が必要となります。

`GitHub > Settings > Developper settings > Personal access tokens　> Generate new token`

上記より、パーソナルアクセストークンを発行しておきます。


####リモートリポジトリへプッシュ
GitHub上で作成したリモートリポジトリには、まだ何のコードも保存されていないので、新規作成したLaravelのプロジェクトをmasterブランチにプッシュします。

```
$ git push origin master
//実行すると、ユーザー名と上記のパーソナルアクセストークンを求められるので入力する。
```
リモートリポジトリにmasterブランチが作成されました。

Git flowでは原則、masterブランチはリリースに用い、開発はdevelopブランチで行います。
今回はdevelopブランチがまだ無いので、ローカルでdevelopブランチを作成してリモートに登録しておきます。

```
//developブランチを作成し、developブランチへ移動
$ git checkout -b develop

//リモートにdevelopブランチを登録
$ git push -u origin develop
```
GitHubで確認すると、画像のようにdevelopブランチが作成されています。
![スクリーンショット 2021-10-12 11.39.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/e76ab5a4-7e8a-9b5c-4f58-f0ef2563984c.png)

これで、Gitでバージョン管理をする準備が整いました。

####開発用のブランチを切る
コードに変更を加える際は、**必ず一度developに戻ってからブランチを切り直します**。
（つい何らかの変更をしてしまいdevelopに戻れなくなった場合は、git stashで作業を待避してからもう一度git checkout developします。）

```
$ git checkout develop
```
コードを変更する前に、ローカルのdevelopブランチを最新状態に更新するため、リモートのdevelopブランチをプルします。

```
//origin上のdevelopブランチを、現在チェックアウトしているブランチ（= develop）に取り込む
$ git pull origin develop
```

ローカルのdevelopブランチを最新状態にできたら、機能を実装するためのfeatureブランチを作ります。
featureブランチの命名規則はチームに寄りけりかと思いますが、今回はfeature/xxxに統一します。

```
//ブランチを作り、作ったブランチに移動する
$ git checkout -b feature/start_livewire
```

ブランチができているか、また作成したブランチに移動できているか確認します。

```
$ git branch
* feature/start_livewire
  develop 
  master
```

これで、コードを編集するためのfeatureブランチが準備できました。

##2. Livewireを使う準備
###【開発】　Livewireを使う準備
####ビューの親ファイルの作成
今回のTodoリスト作成において、作成する画面は、

* 一覧表示
* 新規作成
* 更新

の3つです。

この3つの共通部分となるビューの親ファイルを作成します。

```
$ mkdir resources/views/layouts
$ touch resources/views/layouts/app.blade.php
```

作成したファイルを編集します。

```php:resources/views/layouts/app.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>livewire_todo</title>
    @livewireStyles
</head>
<body>
    @yield('content') 
    @livewireScripts
</body>
</html>
```
【コードの解説】

* livewireを使うため、以下の2点を記述します。
①headタグ内に@livewireStyles 
②bodyの閉じタグ直前に@livewireScripts

* @yield('content')の部分に、後ほど作成するlivewireコンポーネントを埋めることができます。

###【Git】　コミット作成・プルリク作成・次のブランチを切る
* 作業が終わったら、ローカルのdevelopブランチを再度最新の状態にして、featureブランチに developブランチを取り込みます。

```
$ git checkout develop
$ git pull origin develop

//featureブランチへ戻る
$ git checkout feature/start_livewire
```

* commitを作成します。

```
//今いるブランチと変更内容を確認
$ git status

//commit作成
$ git add .
$ git commit
```

* リモートへpushします。

```
$ git push origin feature/start_livewire 
```

* プルリクエストを作成します。

1. Githubのリポジトリページを開く。
2. [Compare & pull request]を押す。
3. Reviewerを指定し、プルリクエストのメッセージを書く。（base:develop / compare:feature/start_livewire を選択する）
4. [Create pull request]を押す。

File changedタブを開くと、ファイルの変更差分を見ることができます。
余計なデバッグコードやコメントが書かれたままになっていないか、コミットのもれや誤りが無いかなど、再度確認しておきます。

またFile changedの画面で各行にマウスカーソルを合わせると、"+"ボタンが出てくるので、これをクリックするとレビューを書くことができます。

レビューが通れば、featureブランチをdevelopブランチにmergeします。

* 次の機能を実装するためのfeatureブランチを切ります。
また一旦developブランチに戻り、ローカルを最新の状態に更新して、新しくfeatureブランチを切ります。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//新しいfeatureブランチを作成
$ git checkout -b feature/todo_create
Switched to a new branch 'feature/todo_create'
```

##3. CREATE機能（新規作成）の実装
###【開発】 CREATE機能を実装するコンポーネントの作成

Livewireでは`$ php artisan make:livewire`コマンドでコンポーネントを作成します。

```
$ php artisan make:livewire todo-create
COMPONENT CREATED  🤙

CLASS: app/Http/Livewire/TodoCreate.php
VIEW:  resources/views/livewire/todo-create.blade.php
```
コマンドを実行すると、ターミナルに表示されている2つのファイルが作成されます。
作成されたファイルのデフォルトの状態は、以下の通りです。

```php:TodoCreate.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;

class TodoCreate extends Component
{
    public function render()
    {
        return view('livewire.todo-create');
    }
}
```
Livewireのコンポーネントには、このようにrender関数があり、一緒に作成されたviewを返します。

```html:todo-create.blade.php
<div>
    {{-- Stop trying to control. --}}
</div>
```
先述の通り、ビューの親ファイルである`resources/views/layouts/app.blade.php`にlivewireを使うための設定を記述し、`@yield('content')`を埋め込んであるので、この親ビューを継承する必要があります。

各ファイルを編集していきます。

```php:todo-create.blade.php
<div>
    <form wire:submit.prevent="save">
        <div>
            <p>タイトル</p>
            <input type="text" wire:model="title">
        </div>

        <div>
            <p>内容</p>
            <textarea wire:model="content"></textarea>
        </div>

        <button type="submit">保存</button>
    </form>
</div>
```
【コードの解説】

* Livewireでは、`wire:イベント.修飾子`でイベントをハンドリングすることができます。
ここでは`wire:submit.prevent="save"`として、formのsubmitが押された時にコンポーネントのsaveメソッド（後述）を実行しています。

* `wire:model`を使用してデータの双方向バインディングを行うことができます。
Livewireはinput要素のイベントをリッスンし、イベントが発動すると、AJAXリクエストを送信して新しいデータでコンポーネントを再レンダリングします。


```TodoCreate.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Todo;

class TodoCreate extends Component
{
    public string $title ="";
    public string $content ="";

    protected array $rules = [
        'title' => 'required|string|max:255',
        'content' => 'required|string|max:255',
    ];

    public function render()
    {
	return view('livewire.todo-create')
            ->extends('layouts.app');
    }

    public function save()
    {
        $this->validate();

        Todo::create([
            "title" => $this->title,
            "content" => $this->content
        ]);

        $this->reset();
    }
}
```
【コードの解説】

* Livewireでは、protectedプロパティに配列の$rulesを定義することで、FormRequestのようにバリデーションを実装できます。
* renderメソッドのビューを返す処理に`->extends('layouts.app')`として、livewireを使う準備を仕込んだ親ファイルを継承します。
* todo-create.blade.phpのformにて`wire:submit.prevent="save"`と呼び出したsaveメソッドを記述しています。
入力された内容がバリデーションを通れば、データをDBに保存します。
Livewireではこのようにresetメソッドを使用して各プロパティを初期値に戻すことができます。

####ルーティングの設定

```web.php
<?php

use App\Http\Livewire\TodoCreate;

Route::get('todos/create', TodoCreate::class)->name('todos.create');　　
```
localhost:8000/todos/createにアクセスすると、フォームが画面表示されます。

![スクリーンショット 2021-10-13 7.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/89a9d39c-64ce-7530-4358-3ea2e10725f2.png)

###【Git】　コミット作成・プルリク作成・次のブランチを切る
CREATE機能を実装したのでGitにあげます。
繰り返しになるので簡単に書いていきます。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//featureブランチへ戻る
$ git checkout feature/todo_create

//今いるブランチと変更内容を確認
$ git status

//commit作成
$ git add .
$ git commit

//リモートへpush
$ git push origin feature/todo_create
```

プッシュできたら、GitHubにてプルリクエストを作成します。
File changedタブでコードを確認するのも忘れずに。

そして次の機能実装に入るため、featureブランチを切ります。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//新しいfeatureブランチを作成
$ git checkout -b feature/todo_read
```

##4. READ機能（一覧表示）の実装
###【開発】 READ機能を実装するコンポーネントの作成
次に一覧表示の機能を実装します。
まずは下記コマンドでコンポーネントを作成します。

```
$ php artisan make:livewire TodoList
COMPONENT CREATED  🤙

CLASS: app/Http/Livewire/TodoList.php
VIEW:  resources/views/livewire/todo-list.blade.php
```

作成された2つのファイルを編集します。

```php:todo-list.blade.php
<div>
    <ul>
        @foreach ($todos as $todo)
        <li>
            <a>{{ $todo->title }}</a>
        </li>
        @endforeach
    </ul>
    <a href="{{ route('todos.create') }}">作成</a>
</div>
```
【コードの解説】

* DBに保存されている全てのTodoを$todosで受け取り、foreach文でリスト表示しています。
* 先に作成した、Todo新規作成画面へのリンクを設置しています。

```TodoList.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Todo;

class TodoList extends Component
{
    public $todos;

    public function mount()
    {
        $this->todos = Todo::all();
    }

    public function render()
    {
        return view('livewire.todo-list')
            ->extends('layouts.app');
    }
}
```
【コードの解説】

* TodoList.phpファイルの中で、ビューへ受け渡す$todosを取得する必要があります。
取得にはライフサイクルフックのmountメソッドを利用します。Livewireでは、mountメソッドがコンストラクターの働きをします。

* 新規作成画面と同様に、レンダリングするviewのレイアウトファイルをextendsで指定しています。

####ルーティングの設定

```web.php
use App\Http\Livewire\TodoList;

Route::get('todos', TodoList::class)->name('todos');
```
localhost:8000/todosへアクセスすると、作成したTodoのタイトル一覧が表示されます。![スクリーンショット 2021-10-12 8.37.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/e52bd9f8-0b7a-01e8-2687-a3ad27562bf2.png)

###【Git】　コミット作成・プルリク作成・次のブランチを切る
READ機能を実装したのでGitにあげます。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
```

もしこの時、自分が作業をしている間に別の人がdevelopブランチを更新していたとすると、ローカルのdevelopブランチを最新の状態にした上でfeatureブランチに取り込む必要があります。

```
//ローカルのdevelopブランチを最新状態に更新
$ git pull origin develop

//featureブランチに取り込む
$ git checkout feature/todo_read
$ git rebase develop
```

featureブランチに、最新のdevelopブランチの内容を取り込んだ上で、commitを作成します。

```
//今いるブランチと変更内容を確認
$ git status

//commit作成
$ git add .
$ git commit

//リモートへpush
$ git push origin feature/todo_read
```

プッシュできたら、GitHubにてプルリクエストを作成します。
File changedタブでコードを確認するのも忘れずに。

そして次の機能実装に入るため、featureブランチを切ります。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//新しいfeatureブランチを作成
$ git checkout -b feature/todo_update
```

##5. UPDATE機能（更新）の実装
###目標の確認
先に、今から作りたいUPDATE機能の完成形を確認しておきます。

* 一覧画面では、Todoのタイトルをクリックすると、更新画面に遷移できるようにします。
![スクリーンショット 2021-10-12 8.38.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/a0e521be-68cf-d42c-de41-d38294831504.png)

* 一覧画面から更新したいTodoをクリックすると、選択したTodoが表示され、内容を書き換えて更新することができます。
![スクリーンショット 2021-10-12 8.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/fac4ffae-b998-4777-6a0a-90f6cc0c2e13.png)


###【開発】 UPDATE機能を実装するコンポーネントの作成
完成形を確認したところで、更新機能を実装していきます。
まずは下記コマンドで、更新機能用のコンポーネントを作成します。

```
$ php artisan make:livewire todo-update

COMPONENT CREATED  🤙

CLASS: app/Http/Livewire/TodoUpdate.php
VIEW:  resources/views/livewire/todo-update.blade.php
```
作成されたファイルを編集します。

```php:todo-update.blade.php
<div>
    <form wire:submit.prevent="update">
        <div>
            <p>タイトル</p>
            <input type="text" wire:model="todo.title">
        </div>

        <div>
            <p>内容</p>
            <textarea wire:model="todo.content">
            </textarea>
        </div>

        <button type="submit">更新</button>
    </form>
</div>
```
【コードの解説】
内容は、CREATEの画面と非常に似ています。

* `wire:submit.prevent="update"`として、formのsubmitが押された時にコンポーネントのupdateメソッド（後述）を実行しています。

* `wire:model`を使用してデータのバインディングを行っています。

``````php:TodoUpdate.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Todo;

class TodoUpdate extends Component
{
    public Todo $todo;

    protected array $rules = [
        'todo.title' => 'required|string|max:255',
        'todo.content' => 'require|string|max:255',
    ];

    public function render()
    {
        return view('livewire.todo-update')
            ->extends('layouts.app');
    }

    public function update()
    {
        $this->validate();
        $this->todo->update();
    }
}
```
【コードの解説】

* publicプロパティの$todoを定義していますが、Livewireではこのようにpublicプロパティにタイプヒンティングを用いてEloquentを設定しておくと、Laravelの暗黙的結合のようにルートのパラメータとモデルのインスタンスを自動的に結合させることができます。

試しに＄todoをデバッグしてみると、以下の通りです。

```
//一覧画面で、idが4のTodoタイトルをクリックした場合

local.DEBUG: {"id":4,"title":"Todo1","content":"Todo1\u306e\u5185\u5bb9","created_at":"2021-10-12T00:43:36.000000Z","updated_at":"2021-10-12T00:43:36.000000Z"}  
```

* updateメソッドでは、バリデーション通ればDBの内容を書き換えています。

####ルーティングの設定
ルートパラメーターにTodoのデータのidを受け取るようにします。

```web.php
use App\Http\Livewire\TodoUpdate;

Route::get('todos/{todo}', TodoUpdate::class)->name('todos.update');
```

一覧画面から更新画面へのリンクを設定します。
更新したいTodoのタイトルをクリックすると、そのTodoの更新画面へ遷移します。
その際データのidをパラメータとして渡します。

```php:todo-list.blade.php
<div>
    <ul>
        @foreach ($todos as $todo)
        <li>
            <a href="{{ route('todos.update',['todo'=>$todo->id]) }}">
            {{ $todo->title }}
            </a>
        </li>
        @endforeach
    </ul>
    <a href="{{ route('todos.create') }}">作成</a>
</div>
```

これでlocalhost:8000/todosにアクセスすると、下記のようにTodoのタイトルをクリックできるようになっています。

![スクリーンショット 2021-10-12 8.38.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/a14914ec-4079-8e23-f214-c3208c407618.png)


更新したいTodoのタイトルをクリックすると、更新画面へ遷移します。
内容を書き換えて更新ボタンを押すと、リロードされることなくDBのデータが更新されます。
![スクリーンショット 2021-10-12 8.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/f1262428-5694-c239-a591-4718ff0fa284.png)

###【Git】　コミット作成・プルリク作成・次のブランチを切る
UPDATE機能を実装したのでGitにあげます。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//featureブランチへ戻る
$ git checkout feature/todo_update

//今いるブランチと変更内容を確認
$ git status

//commit作成
$ git add .
$ git commit

//リモートへpush
$ git push origin feature/todo_update
```

プッシュできたら、GitHubにてプルリクエストを作成します。
File changedタブでコードを確認するのも忘れずに。

そして次の機能実装に入るため、featureブランチを切ります。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//新しいfeatureブランチを作成
$ git checkout -b feature/todo_delete
```

##6. DELETE機能（削除）の実装 
###【開発】　一覧画面に削除ボタンを設置
現在、一覧画面には保存されているTodoのタイトルがリスト表示されています。
このタイトルの横に、削除ボタンを設置します。

今回は新しく作るコンポーネントはありません。既存ファイルを修正します。

```php:todo-list.blade.php
<div>
    <ul>
        @foreach ($todos as $todo)
        <li>
            <a href="{{ route('todos.update',['todo'=>$todo->id]) }}">{{ $todo->title }}</a>
            <button wire:click="delete({{ $todo->id }})">削除</button>
        </li>
        @endforeach
    </ul>
    <a href="{{ route('todos.create') }}">作成</a>
</div>
```
削除ボタンのクリックイベントが発動すると、該当のデータのidを引数として、TodoListコンポーネントのdeleteメソッドが呼び出されます。

このdeleteメソッドをコンポーネントに追加します。

```TodoList.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Todo;

class TodoList extends Component
{
    public $todos;

    public function mount()
    {
        $this->todos = Todo::all();
    }

    public function render()
    {
        return view('livewire.todo-list')
            ->extends('layouts.app');
    }

    public function delete($id)     //追記部分
    {
        Todo::find($id)->delete();
        $this->todos = Todo::all();
    }
}
```
削除ボタンを押したTodoをdeleteメソッドで削除します。

ただしこれだけでは、DBからはデータが消えるもののページ上には削除したTodoも表示され続けるため、再度DBに保存されているTodoを取得しています。

これで、削除ボタンを押せば該当のTodoが削除されるようになりました。

![スクリーンショット 2021-10-12 9.43.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/132ff432-34bc-726e-949d-c15757bc6797.png)

###【Git】　コミット作成・プルリク作成・次のブランチを切る
DELETE機能を実装したのでGitにあげます。

```
//ローカルのdevelopブランチを最新の状態に更新
$ git checkout develop
$ git pull origin develop

//featureブランチへ戻る
$ git checkout feature/todo_delete

//今いるブランチと変更内容を確認
$ git status

//commit作成
$ git add .
$ git commit

//リモートへpush
$ git push origin feature/todo_delete
```

プッシュできたら、GitHubにてプルリクエストを作成します。
File changedタブでコードを確認するのも忘れずに。


CRUD機能が実装できたので、これで終わります。


<br><br>
##参考記事

https://laravel-livewire.com/

https://readouble.com/livewire/2.x/ja/rendering-components.html

https://reffect.co.jp/laravel/laravel-livewire

https://kobatech-blog.com/livewire/

https://qiita.com/siida36/items/880d92559af9bd245c34#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%A7master%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E6%9B%B4%E6%96%B0%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B

https://qiita.com/shh-nkmr/items/fde133cbdfa5f0092be1