##やりたいこと
今回のテーマは、以下の2つです。
- LaravelのLivewireの使い方を、CRUD機能を持ったTodoリストを実装しながら解説する
- Todoリストの実装を、チーム開発を想定したGit flowの流れに沿ってソースコード管理する
Gitの基本的な使い方やチーム開発の運用について学んだので、コミットしてプッシュしてプルリクエストを作成して…というような手順を実践してみたいなと思っていました。
せっかくならGitの練習のためだけのサンプルコードで行うより、実際に何か開発しながらチーム開発を想定してソースコード管理をやってみようということで、Todoリストの実装をGit flowに沿って管理してみます。
##全体の流れ
###Todoリスト作成の手順
- Laravelの新規プロジェクト作成
- Livewireを使う準備
- CREATE機能(新規作成)の実装
- READ機能(一覧表示)の実装
- UPDATE機能(更新)の実装
- DELETE機能(削除)の実装
これらの各機能を実装する度に、下記「Gitでのチーム開発の手順」を繰り返し、ソースコード管理を行なっていきます。
###Gitでのチーム開発の手順
- ローカルリポジトリでdevelop(開発)ブランチに入る
- リモートリポジトリのdevelopブランチをローカルのdevelopブランチにプルして、ローカルのdevelopブランチを最新の状態にする。
- ローカルでdevelopブランチからfeature(機能)ブランチを作り、そこで開発する。
- 変更点をローカルでcommitする。
- 作業が終わったら、ローカルのdevelopブランチを再度最新の状態にして、featureブランチに developブランチを取り込む。(rebase or merge)
- ローカルのfeatureブランチの内容を、リモートリポジトリの同名のブランチへpushする。
- リモートのfeatureブランチからリモートのdevelopブランチへ、プルリクエストを発行する。
- コードレビューをしてもらう。
- コードレビューが通れば、レビュアーがリモートのdevelopブランチへ featureブランチをmergeする。
- リモートの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ブランチが作成されています。
これで、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
作成したファイルを編集します。
<!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
- プルリクエストを作成します。
- Githubのリポジトリページを開く。
- [Compare & pull request]を押す。
- Reviewerを指定し、プルリクエストのメッセージを書く。(base:develop / compare:feature/start_livewire を選択する)
- [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
namespace App\Http\Livewire;
use Livewire\Component;
class TodoCreate extends Component
{
public function render()
{
return view('livewire.todo-create');
}
}
Livewireのコンポーネントには、このようにrender関数があり、一緒に作成されたviewを返します。
<div>
{{-- Stop trying to control. --}}
</div>
先述の通り、ビューの親ファイルであるresources/views/layouts/app.blade.php
にlivewireを使うための設定を記述し、@yield('content')
を埋め込んであるので、この親ビューを継承する必要があります。
各ファイルを編集していきます。
<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リクエストを送信して新しいデータでコンポーネントを再レンダリングします。
<?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メソッドを使用して各プロパティを初期値に戻すことができます。
####ルーティングの設定
<?php
use App\Http\Livewire\TodoCreate;
Route::get('todos/create', TodoCreate::class)->name('todos.create');
localhost:8000/todos/createにアクセスすると、フォームが画面表示されます。
###【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つのファイルを編集します。
<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新規作成画面へのリンクを設置しています。
<?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で指定しています。
####ルーティングの設定
use App\Http\Livewire\TodoList;
Route::get('todos', TodoList::class)->name('todos');
localhost:8000/todosへアクセスすると、作成したTodoのタイトル一覧が表示されます。
###【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機能の完成形を確認しておきます。
###【開発】 UPDATE機能を実装するコンポーネントの作成
完成形を確認したところで、更新機能を実装していきます。
まずは下記コマンドで、更新機能用のコンポーネントを作成します。
$ php artisan make:livewire todo-update
COMPONENT CREATED 🤙
CLASS: app/Http/Livewire/TodoUpdate.php
VIEW: resources/views/livewire/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
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