Laravel Sail でプロジェクト作成から簡単なCRUD機能を持つアプリを実装する方法のメモ。
プロジェクト作成
curl -s "https://laravel.build/post-app?with=mysql" | bash
コンテナ起動
cd post-app sail up -d
モデル作成
モデル作成と同時にマイグレーションファイルとリソースコントローラファイルを作成する
sail artisan make:model Post -mr
INFO Model [app/Models/Post.php] created successfully. INFO Migration [database/migrations/2023_01_23_165723_create_posts_table.php] created successfully. INFO Controller [app/Http/Controllers/PostController.php] created successfully.
フォームリクエスト作成
sail artisan make:request PostRequest
INFO Request [app/Http/Requests/PostRequest.php] created successfully.
マイグレーションファイル編集
upメソッドを編集してカラム追加
# /database/migrations/2023_01_22_004803_create_posts_table.php
$table->string('title');
$table->text('description');
編集後のupメソッド
# /database/migrations/2023_01_22_004803_create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
$table->timestamps();
});
}
マイグレーション実行
sail artisan migrate
Postモデル編集
fillable設定
protected $fillable = ['title', 'description'];
編集後のPostクラス
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'description'];
}
PostRequest編集
authorizeメソッド修正
false を true に変更する
# /app/Http/Requests/PostRequest.php
public function authorize()
{
return true;
}
バリデーションルール設定
# /app/Http/Requests/PostRequest.php
public function rules()
{
return [
'title' => ['required', 'max:80'],
'description' => ['required']
];
}
リソースコントローラ編集
index
# /app/Http/Controllers/PostController.php
public function index()
{
$posts = Post::latest()->paginate(10);
return view('posts.index', compact('posts'));
}
create
# /app/Http/Controllers/PostController.php
public function create()
{
return view('posts.create');
}
store
# /app/Http/Controllers/PostController.php
public function store(PostRequest $request)
{
Post::create($request->validated());
return redirect()->route('posts.index')->with('message', '投稿の作成が完了しました。');
}
show
# /app/Http/Controllers/PostController.php
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
edit
# /app/Http/Controllers/PostController.php
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
update
# /app/Http/Controllers/PostController.php
public function update(PostRequest $request, Post $post)
{
$post->update([
'title' => $request->title,
'description' => $request->description
]);
return redirect()->route('posts.index')->with('message', '投稿の更新が完了しました。');
}
destroy
# /app/Http/Controllers/PostController.php
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')->with('message', '投稿の削除が完了しました。');
}
Bladeテンプレート
以下、5つのテンプレートファイルを用意します。
# /resources/views/components/app.blade.php # /resources/views/posts/index.blade.php # /resources/views/posts/create.php # /resources/views/posts/edit.php # /resources/views/posts/show.php
app.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laravel CRUDサンプル</title>
</head>
<body>
{{ $slot }}
</body>
</html>
index.blade.php
<x-app>
@if (session()->has('message'))
<div>{{ session('message') }}</div>
@endif
<div>
<button onclick="location.href='{{ route('posts.create') }}'" >新規作成</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>タイトル</th>
<th>本文</th>
<th>作成日時</th>
<th>更新日時</th>
<th colspan="2">編集・削除</th>
</tr>
</thead>
<tbody>
@foreach ($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td><a href="{{ route('posts.show', $post->id) }}">{{ $post->title }}</a></td>
<td>{!! nl2br( htmlspecialchars($post->description) ) !!}</td>
<td>{{ $post->created_at }}</td>
<td>{{ $post->updated_at }}</td>
<td>
<button onclick="location.href='{{ route('posts.edit', $post->id) }}'" >編集</button>
</td>
<td>
<form action="{{ route('posts.destroy',$post->id) }}" method="POST" onsubmit="return confirm('削除してもよろしいですか?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button type="submit">削除</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</x-app>
create.blade.php
<x-app>
<form method="POST" action="{{ route('posts.index') }}">
@csrf
<div>
<div>
<label>タイトル</label>
</div>
<div>
<input type="text" name="title" value="{{old('title')}}">
</div>
@error('title')
<span>{{ $message }}</span>
@enderror
</div>
<div>
<div>
<label>本文</label>
</div>
<div>
<textarea name="description" rows="4"> {{old('description')}}</textarea>
</div>
@error('description')
<span>{{ $message }}</span>
@enderror
</div>
<button type="submit">保存</button>
</form>
</x-app>
edit.blade.php
<x-app>
<form method="POST" action="{{ route('posts.update',$post->id) }}">
@csrf
@method('PUT')
<div>
<div>
<label>タイトル</label>
</div>
<div>
<input type="text" name="title" value="{{old('title',$post->title)}}">
</div>
@error('title')
<span>{{ $message }}</span>
@enderror
</div>
<div>
<div>
<label>本文</label>
</div>
<div>
<textarea name="description" rows="4"> {{old('description',$post->description)}}</textarea>
</div>
@error('description')
<span>{{ $message }}</span>
@enderror
</div>
<button type="submit">更新</button>
</form>
</x-app>
show.blade.php
<x-app>
<div>
<label for="title">タイトル</label>
<p>{{old('title',$post->title)}}</p>
</div>
<div>
<label for="description">本文</label>
<p>{{old('description',$post->description)}}</p>
</div>
<button onclick="location.href='{{ route('posts.index') }}'" >戻る</button>
</x-app>
ルーティング設定
use宣言 追加
use App\Http\Controllers\PostController;
ルート設定
まとめて設定した場合
Route::resource('posts', PostController::class);
バラして設定した場合
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::get('/posts/{post}/edit', [PostController::class, 'ineditdex'])->name('posts.edit');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
ルーティング設定状況確認
sail artisan route:list
GET|HEAD posts ...............................posts.index › PostController@index POST posts ...............................posts.store › PostController@store GET|HEAD posts/create ......................posts.create › PostController@create GET|HEAD posts/{post} ..........................posts.show › PostController@show PUT|PATCH posts/{post} ......................posts.update › PostController@update DELETE posts/{post} ....................posts.destroy › PostController@destroy GET|HEAD posts/{post}/edit .....................posts.edit › PostController@edit
リソースコントローラにより処理されるアクション一覧
HTTPメソッド | URI | アクション | ルート名 |
GET | /posts | index | posts.index |
GET | /posts/create | create | posts.create |
POST | /posts | store | posts.store |
GET | /posts/{post} | show | posts.show |
GET | /posts/{post} | edit | posts.edit |
PUT/PATCH | /posts/{post}/edit | update | posts.update |
DELETE | /posts/{post} | destroy | posts.destroy |
動作環境情報
"macOS Ventura" 13.1 "Docker Desktop" 4.15.0 "Laravel Sail" "Laravel Framework" 9.48.0
コメント