Laravelとは
LaravelはPHPでWebアプリケーションを作るためのフレームワークです。URLを受け取り、入力を確認し、データベースを操作し、HTMLやJSONを返すまでに必要な部品を、決まった構造で組み合わせられます。
- ブログ、掲示板、日報などの画面とデータ管理
- ログイン、パスワードリセット、メール認証
- JavaScriptアプリやスマートフォン向けのJSON API
- キュー、定期実行、メール、ファイル保存
- HTTPリクエスト、データベース、画面の自動テスト
フレームワークは、すべてを自動で正解にしてくれる魔法ではありません。Laravelが用意した約束に沿って責務を分けることで、コードが増えても調査と変更をしやすくする道具です。
準備と環境構築
Laravel 13ではPHP 8.3以上が必要です。Composer、Laravelインストーラー、Node.jsとnpmまたはBunを用意します。最初はSQLiteを選ぶと、別のDBサーバーを起動せずに学習を始められます。
php --version
composer --version
node --version
npm --versioncomposer global require laravel/installer
laravel new note-board
cd note-boardインストーラーの質問では、テストフレームワーク、データベース、スターターキットを選べます。ここでは認証を後から理解するため、まずは最小構成で進めます。
npm install && npm run build
composer run devhttp://localhost:8000./vendor/bin/が必要な場合は、プロジェクト内の依存関係を使っているかも確認しましょう。プロジェクト構成を読む
最初から全ファイルを暗記する必要はありません。自分が変更する代表的な場所と役割を知り、処理を置く場所に迷わないことが目標です。
app/Models/ データを表すモデル
app/Http/Controllers/ 画面やAPIの処理
app/Http/Requests/ 入力検証をまとめるクラス
resources/views/ Bladeテンプレート
routes/web.php ブラウザー向けのルート
routes/api.php API向けのルート(必要に応じて有効化)
database/migrations/ テーブル構造の変更履歴
database/seeders/ 学習用データの投入
tests/Feature/ アプリ全体に近いテスト
config/ 設定ファイル
storage/ ログや生成ファイル.envには環境ごとに異なる設定を書きます。パスワードやAPIキーが入る可能性があるので、Gitへコミットしません。APP_KEYは暗号化などに使われる重要な値です。
リクエストの流れを追う
画面が表示されるまでの経路を追えると、Laravelの記法が急に分かりやすくなります。たとえばGET /greetingを受け取り、名前をビューへ渡して表示します。
use Illuminate\Support\Facades\Route;
Route::get('/greeting', function () {
return view('greeting', ['name' => 'Mity']);
});<h1>こんにちは、{{ $name }}さん</h1>ブラウザーで/greetingを開くと、次のHTMLが生成されます。
こんにちは、Mityさん- ブラウザーがGETリクエストを送る
- Laravelが
Route::getに一致させる - クロージャーがビューへ
$nameを渡す - BladeがHTMLを生成してレスポンスを返す
ルーティング
ルートはHTTPメソッド、URL、実行する処理の組み合わせです。同じURLでもGETは表示、POSTは登録というように役割を分けます。
Route::get('/posts', [PostController::class, 'index'])
->name('posts.index');
Route::get('/posts/create', [PostController::class, 'create'])
->name('posts.create');
Route::post('/posts', [PostController::class, 'store'])
->name('posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])
->name('posts.show');URLへ直接文字列を埋め込むより、名前付きルートとroute()を使うと、URLを変更してもリンクの修正箇所を減らせます。
<a href="{{ route('posts.index') }}">投稿一覧</a>
<a href="{{ route('posts.show', $post) }}">{{ $post->title }}</a>php artisan route:list{post}のような値は、次のコントローラーで受け取ります。Laravelの暗黙のモデル結合を使うと、IDに対応するPostを自動取得できます。ルーティングとBladeをもっと詳しく学ぶ場合はルーティングとBladeへ進んでください。
コントローラーで処理を分ける
ルートへ長い処理を書き続けると、入力、DB、画面の責務が混ざります。コントローラーを作り、リクエストを受けて必要な処理へ橋渡しします。
php artisan make:controller PostControllernamespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\View\View;
class PostController extends Controller
{
public function index(): View
{
$posts = Post::query()->latest()->paginate(10);
return view('posts.index', compact('posts'));
}
}latest()やpaginate()はモデルへ問い合わせる処理、view()は表示へ渡す処理です。コントローラーにHTML文字列や複雑なSQLを詰め込みすぎないようにします。
BladeでHTMLを作る
BladeはLaravelのテンプレートエンジンです。{{ }}で値を表示し、通常はHTMLとして安全にエスケープされます。条件分岐や繰り返しも、HTMLの流れを保ったまま書けます。
<h1>投稿一覧</h1>
@forelse ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ $post->body }}</p>
<a href="{{ route('posts.show', $post) }}">続きを読む</a>
</article>
@empty
<p>まだ投稿がありません。</p>
@endforelse
{{ $posts->links() }}共通レイアウトは@extendsと@sectionで分け、部品は@includeやBladeコンポーネントへまとめます。
<!-- resources/views/layouts/app.blade.php -->
<!doctype html>
<html lang="ja">
<body>
<header>Note Board</header>
@yield('content')
</body>
</html>
<!-- posts/index.blade.php -->
@extends('layouts.app')
@section('content')
<h1>投稿一覧</h1>
@endsection{{ $value }}を使います。HTMLを解釈させる{!! $value !!}は、信頼できる生成済みHTMLに限り、入力値へ使わないでください。フォームとCSRF
表示用のGETと、データを変更するPOSTを分けます。LaravelのWebルートでPOSTフォームを作るときは、@csrfでCSRFトークンを埋め込みます。これにより、別サイトから勝手に送信されるリクエストを検査できます。
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<label for="title">タイトル</label>
<input id="title" name="title" value="{{ old('title') }}" required>
<label for="body">本文</label>
<textarea id="body" name="body" required>{{ old('body') }}</textarea>
<button type="submit">保存</button>
</form><form method="POST" action="{{ route('posts.update', $post) }}">
@csrf
@method('PUT')
<input name="title" value="{{ old('title', $post->title) }}">
<button type="submit">更新</button>
</form>
<form method="POST" action="{{ route('posts.destroy', $post) }}">
@csrf
@method('DELETE')
<button type="submit">削除</button>
</form>バリデーションで入力を確認する
フォームの値は、利用者が正しく入力するとは限りません。保存前に必須、文字数、形式などのルールを確認し、失敗したら入力画面へ戻します。
use Illuminate\Http\Request;
public function store(Request $request)
{
$validated = $request->validate([
'title' => ['required', 'string', 'max:100'],
'body' => ['required', 'string', 'max:5000'],
]);
Post::create($validated);
return redirect()
->route('posts.index')
->with('status', '投稿を保存しました。');
}@error('title')
<p class="error">{{ $message }}</p>
@enderror
@if (session('status'))
<p>{{ session('status') }}</p>
@endif入力を検証した後は、検証済みの$validatedだけを保存処理へ渡します。大量代入を使うモデルでは$fillableなどの設定も確認し、利用者が変更してはいけない列を受け取らないようにします。
フォーム検証の詳しい例と練習問題はフォームとバリデーションにまとめています。
データベースとマイグレーション
マイグレーションは、テーブル構造の変更をコードで記録する仕組みです。手作業でDBを編集するのではなく、チーム全員が同じ履歴を適用できるようにします。
php artisan make:model Post -mf
php artisan migrateSchema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title', 100);
$table->text('body');
$table->string('image_path')->nullable();
$table->timestamps();
});開発中に最後の変更を取り消して作り直すならphp artisan migrate:fresh --seedがあります。ただし、このコマンドはDBのテーブルとデータをすべて削除するため、本番環境では実行しません。
- 空欄を許す列か、必須の列か
- 文字列の最大長や数値の範囲は何か
- 削除された利用者と投稿をどう扱うか
- 検索や並び替えに必要なインデックスは何か
Eloquentでデータを扱う
Eloquentは、データベースの行をモデルオブジェクトとして扱うORMです。便利なメソッドを使いながらも、実際にはSQLが発行されることを意識し、必要なデータだけを取得します。
class Post extends Model
{
protected $fillable = ['title', 'body', 'image_path'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
// 検索・作成・更新・削除
$posts = Post::where('title', 'like', '%Laravel%')
->latest()
->get();
$post = Post::create($validated);
$post->update(['title' => '更新後のタイトル']);
$post->delete();php artisan tinker
>>> Post::count();
= 3
>>> Post::latest()->first()->title;
= "Laravelを学び始めました"Post::with('user')->latest()->get()のようにEager Loadingを検討し、クエリログや実際の件数で確認します。マイグレーション、モデル、CRUDの詳しい手順はデータベースとEloquentで練習できます。
CRUDを一周する
投稿アプリの基本は、Create(作成)、Read(読込)、Update(更新)、Delete(削除)です。表示・フォーム・保存・編集・削除をルートとコントローラーへ対応させます。
Route::resource('posts', PostController::class);| メソッド | URL | 目的 |
|---|---|---|
| GET | /posts | 一覧(index) |
| GET | /posts/create | 作成フォーム(create) |
| POST | /posts | 保存(store) |
| GET | /posts/{post} | 詳細(show) |
| GET | /posts/{post}/edit | 編集フォーム(edit) |
| PUT/PATCH | /posts/{post} | 更新(update) |
| DELETE | /posts/{post} | 削除(destroy) |
まず一覧を表示し、次に新規作成、編集、削除を一つずつ追加します。各段階で正常な入力だけでなく、存在しないID、空欄、他人の投稿も確認すると、後の不具合を早く見つけられます。
モデル同士の関係を表す
投稿は利用者に属し、利用者は複数の投稿を持ちます。リレーションをモデルへ定義すると、関連データを意味のあるコードで取得できます。
use Illuminate\Database\Eloquent\Relations\HasMany;
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
// 利用者の投稿を取得
$user->posts()->latest()->get();use Illuminate\Database\Eloquent\Relations\BelongsTo;
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
echo $post->user->name;多対多ならbelongsToManyと中間テーブルを使います。関係をコードにしたら、外部キー、削除時の動作、一覧時のクエリ数も合わせて設計します。
認証と認可
認証は「誰か」を確認すること、認可は「何をしてよいか」を確認することです。ログインできても、他人の投稿まで編集できてよいとは限りません。
Route::middleware('auth')->group(function () {
Route::resource('posts', PostController::class)
->except(['index', 'show']);
});public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
// コントローラー
$this->authorize('update', $post);ログイン画面は公式スターターキットを利用すると、登録、ログイン、パスワードリセットなどの土台を用意できます。パスワードを自作の暗号化で保存したり、認証を自己流で置き換えたりせず、Laravelの標準機能と公式資料を確認しましょう。
認証とAPIトークンを詳しく学ぶ場合は認証とAPIへ進んでください。
JSON APIを作る
LaravelはHTML画面だけでなく、JSONを返すAPIのバックエンドにも使えます。APIでは、成功時と失敗時のステータスコード、返す項目、認証方法を先に決めます。
use App\Models\Post;
use Illuminate\Http\JsonResponse;
Route::get('/posts', function (): JsonResponse {
return response()->json(
Post::latest()->get(['id', 'title', 'body'])
);
});[
{
"id": 3,
"title": "Laravelを学び始めました",
"body": "まずはルートを動かします。"
}
]実際のアプリではAPI Resourceで公開する項目を定義し、認証が必要なルートにはSanctumなどを使います。モデルをそのまま返すと、意図しない列を公開する恐れがあるため注意が必要です。
サービス、メール、キュー
処理が増えたら、コントローラーから業務処理をサービスクラスへ分けます。たとえば投稿保存と画像処理、通知を別の責務にするとテストしやすくなります。
final class PublishPost
{
public function handle(User $user, array $data): Post
{
return $user->posts()->create([
'title' => $data['title'],
'body' => $data['body'],
]);
}
}すぐ返す必要のないメール送信や重い処理は、ジョブをキューへ渡します。キューワーカーは別プロセスなので、ローカルで実行する場合もphp artisan queue:workを起動し、失敗したジョブや再試行を確認します。
php artisan schedule:list
php artisan queue:workテストで動作を守る
テストは、書いた直後だけでなく、将来の変更で既存機能が壊れていないかを確認するためのコードです。LaravelではUnitテストとFeatureテストを使い分けますが、画面・DB・認証まで確認するFeatureテストが特に実践的です。
php artisan make:test PostTest
php artisan testuse App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('投稿一覧を表示できる', function () {
$post = Post::factory()->create([
'title' => 'テスト投稿',
]);
$this->get('/posts')
->assertOk()
->assertSee('テスト投稿');
});test('タイトルが空なら保存しない', function () {
$response = $this->post('/posts', [
'title' => '',
'body' => '本文',
]);
$response->assertSessionHasErrors('title');
$this->assertDatabaseCount('posts', 0);
});テストでは、DBや外部メールへ本物の処理を送らない設定を使います。正常系だけでなく、未認証、入力エラー、権限不足、存在しないデータもテストすると、利用者の操作に近い品質を確認できます。
公開前の確認
ローカルで動くことと、インターネットへ安全に公開できることは別です。公開前には設定、権限、ログ、バックアップ、HTTPS、DB接続を確認します。
.envや秘密鍵をリポジトリへ含めていない- 本番の
APP_DEBUGがfalseになっている - Webサーバーの公開先がプロジェクトの
publicだけになっている - 入力検証、CSRF、認証、認可、出力エスケープを確認した
- マイグレーションとバックアップの手順がある
- ログにパスワードやトークンを出力していない
- テストと本番用のメール・ストレージ設定を分けている
php artisan optimize
php artisan migrate --forcemigrate --forceは確認なしでDB構造を変更します。バックアップ、適用するマイグレーション、ロールバック方法を確認してから実行します。テスト、デプロイ、運用の流れをまとめて復習する場合はテストとデプロイを読んでください。
総合練習:読書メモアプリを作る
ここまでの知識を使い、ログインした利用者が読書メモを登録・一覧・編集・削除できるアプリを作ってください。既存の投稿アプリをそのまま写すのではなく、要件を自分で分解する練習です。
課題1:データ設計
booksテーブルとnotesテーブルを設計します。読書メモは利用者と本に属し、タイトル、本文、評価(1〜5)、読了日を持つものとします。
課題2:画面とCRUD
本の一覧、メモの一覧、メモ作成、編集、削除を実装します。名前付きルート、Resource Controller、Bladeレイアウトを使い、空の一覧とページネーションも表示します。
課題3:安全性
未ログイン利用者は作成・更新・削除できないようにします。さらに、別の利用者のメモをURLへ直接入力しても編集・削除できないPolicyを作り、フォームにはCSRF、保存前にはバリデーションを追加します。
課題4:テスト
「ログイン利用者はメモを作成できる」「タイトルが空なら保存されない」「他人のメモは更新できない」「一覧に自分のメモが表示される」をFeatureテストにしてください。
完成条件と発展課題
- マイグレーションを最初から適用してDBを作れる
- SeederまたはFactoryで確認用データを作れる
- 正常系・入力エラー・権限エラーの画面を確認できる
- テストを実行して全件成功する
- 発展として、画像、検索、タグ、多対多リレーション、JSON APIのどれかを追加する
次に学ぶこと
Laravelの基本を一周したら、興味のあるテーマを一つ選び、サンプルを改造してテストまで書きます。公式ドキュメントは、インストール、ルーティング、Blade、バリデーション、Eloquent、認証、テストの順で参照すると迷いにくくなります。
詳しい仕様はLaravel公式ドキュメント(13.x)も確認してください。
