公開日 2026-03-24

Laravel入門(Route / Controller / View / Model 最小構成)

Laravel 13 の最初のプロジェクトを Docker だけで作り、Route / Controller / View / Model を SQLite 付きで一通りつなげる。

目次

  1. 前提環境
  2. 1. ゴールと非対象
  3. 2. 作業ディレクトリを用意して Laravel プロジェクトを作る
  4. 3. 開発サーバーを起動して初期画面を確認する
  5. 4. Model と migration を追加する
  6. 5. Route / Controller / View をつなぐ
  7. 6. サンプルデータを入れる
  8. 7. 一覧ページを確認しながら役割を整理する
  9. 8. よくある詰まりと次の一歩

Laravel をまだ触っておらず、最初の 1 画面を作りながら Route / Controller / View / Model の役割をまとめてつかみたい読者向けです。
ゴールは、Laravel 13 の新規プロジェクト作成から SQLite を使った本一覧ページの表示まで。

補助導線として先に触っておくと入りやすい記事:

この 2 本を未読でも、以下の手順だけで進められる構成です。

前提環境

  • Windows 11
  • WSL2(Ubuntu)
  • VS Code(Remote - WSL)
  • Docker Desktop(WSL 連携有効)

以降のコマンドは、特記がない限り WSL 側ターミナルで実行します。

1. ゴールと非対象

この記事で到達する状態:

  • Laravel の新規プロジェクトを作成できる
  • http://localhost:8000 で開発サーバーを確認できる
  • Route / Controller / View / Model を使って本一覧ページを表示できる

今回は、Laravel の最初の導線を 1 本でつかむことに絞ります。
認証やフロントエンド構築まで広げると、Route / Controller / View / Model の役割が見えにくくなるからです。

扱わない内容は次のとおりです。

  • Breeze / Jetstream などの認証導入
  • React / Vue / Inertia
  • PostgreSQL / MySQL への切り替え
  • テスト、CI、デプロイ

2. 作業ディレクトリを用意して Laravel プロジェクトを作る

最初に、WSL と Docker が見えているかを確認します。

PowerShell:

wsl -l -v

WSL(Ubuntu):

docker --version
docker compose version

開始位置は ~/projects/laravel-intro-guide-demo です。

mkdir -p ~/projects/laravel-intro-guide-demo
cd ~/projects/laravel-intro-guide-demo
code .

Laravel 13 の公式 Installation では Laravel Installer から starter kit を選ぶ流れが主線です。
ここでは既存シリーズを Docker 中心でそろえるため、ホスト側へ PHP や Composer を直接入れずに済む composer:2 コンテナから create-project を実行します。

docker run --rm -u "$(id -u):$(id -g)" -v "$(pwd):/app" -w /app composer:2 create-project laravel/laravel .

-u "$(id -u):$(id -g)" を付けているのは、生成されたファイルの所有者を WSL 側の自分にそろえるためです。
ここを外すと Laravel 一式が root 所有になり、VS Code で保存するときに権限エラーになることがあります。

生成された composer.json には php:^8.3laravel/framework:^13.0
最初は雛形のまま進めます。追加の package はまだ不要。

続いて compose.yml を作成。
以降のコマンドを docker compose exec app ... にそろえるためです。

compose.yml:

services:
  app:
    image: composer:2
    user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
    working_dir: /app
    volumes:
      - ./:/app
    ports:
      - "8000:8000"
    command: php artisan serve --host=0.0.0.0 --port=8000

同じシェルで次も実行して、docker compose 側でも自分の UID / GID を使うようにします。

export LOCAL_UID="$(id -u)"
export LOCAL_GID="$(id -g)"

起動前に Laravel の環境情報を見たい場合は、次を実行します。

docker compose run --rm app php artisan about --only=environment

run --rm はコンテナを一時起動して即削除します。以降の docker compose exec app ... はコンテナが起動済みの前提で使うコマンドです。

Laravel VersionPHP Version が表示されれば、雛形の作成は完了です。

3. 開発サーバーを起動して初期画面を確認する

ここでは、生成直後の Laravel がそのまま起動することを先に確かめます。

docker compose up -d
docker compose logs app --tail 20

ログに Server running on [http://0.0.0.0:8000] が出たら、ブラウザで http://localhost:8000 を開いてください。
初期の welcome 画面が表示されれば、Laravel 自体の起動確認は完了です。

curl -I http://localhost:8000
  • 期待結果: HTTP/1.1 200 OK
Laravelのwelcome画面

8000 番ポートが埋まっている場合は、compose.yml の左側を 8001:8000 に変えて docker compose up -d をやり直してください。

4. Model と migration を追加する

次は一覧表示に使う Book モデルです。

docker compose exec app php artisan make:model Book -m

このコマンドで、次の 2 つが生成されます。

  • app/Models/Book.php
  • database/migrations/*_create_books_table.php

migration の timestamp は実行時刻ごとに変わるため、ファイル名の先頭は各自で異なります。
生成された *_create_books_table.php を、次の内容に置き換えてください。

database/migrations/*_create_books_table.php:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('author');
            $table->unsignedSmallInteger('published_year');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('books');
    }
};

app/Models/Book.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    protected $fillable = [
        'title',
        'author',
        'published_year',
    ];
}

今回は追加 DB コンテナを使わず、Laravel 生成直後の SQLite 前提で進めます。
最初の 1 本では DB サーバーの構築より、Model と画面のつながりを先に見たほうが流れをつかみやすいからです。

5. Route / Controller / View をつなぐ

続けて controller を作成します。

docker compose exec app php artisan make:controller BookController

最終的に使うファイルは 3 つです。

  • routes/web.php(既存ファイルを編集)
  • app/Http/Controllers/BookController.php(artisan が生成)
  • resources/views/books/index.blade.php(自分で作成)

routes/web.php:

<?php

use App\Http\Controllers\BookController;
use Illuminate\Support\Facades\Route;

Route::get('/', [BookController::class, 'index']);

app/Http/Controllers/BookController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Book;
use Illuminate\Contracts\View\View;

class BookController
{
    public function index(): View
    {
        $books = Book::query()
            ->orderBy('id')
            ->get();

        return view('books.index', [
            'books' => $books,
        ]);
    }
}

次に View ファイルを用意します。resources/views/ 直下には welcome.blade.php しかないので、books/ ディレクトリを作ってその中にファイルを置きます。

mkdir -p resources/views/books
touch resources/views/books/index.blade.php

resources/views/books/index.blade.php(新規作成):

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel Intro Books</title>
    <style>
        body {
            margin: 0;
            font-family: "Segoe UI", sans-serif;
            background: #f5f7fb;
            color: #1f2937;
        }

        main {
            max-width: 720px;
            margin: 48px auto;
            padding: 24px;
        }

        .card {
            background: #ffffff;
            border-radius: 16px;
            padding: 24px;
            box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
        }

        h1 {
            margin-top: 0;
            font-size: 2rem;
        }

        ul {
            padding-left: 20px;
        }

        li + li {
            margin-top: 12px;
        }

        .meta {
            color: #4b5563;
            font-size: 0.95rem;
        }
    </style>
</head>
<body>
    <main>
        <section class="card">
            <h1>Laravelで作った最初の一覧ページ</h1>
            <p>BookController が Model から受け取ったデータを Blade で表示しています。</p>

            <ul>
                @forelse ($books as $book)
                    <li>
                        <strong>{{ $book->title }}</strong><br>
                        <span class="meta">{{ $book->author }} / {{ $book->published_year }}</span>
                    </li>
                @empty
                    <li>books テーブルにデータがまだありません。</li>
                @endforelse
            </ul>
        </section>
    </main>
</body>
</html>

Route は URL と処理の対応付け、Controller は取得したデータの受け渡し、View は HTML の描画に集中します。
この分け方が見えてくると、Laravel の基本構成が読みやすくなります。

View [books.index] not found. と出た場合は、resources/views/books/index.blade.php のディレクトリ名とファイル名を見直してください。

6. サンプルデータを入れる

このままでは books テーブルが空なので、一覧に何も出ません。
最初のデータ投入は Seeder で行います。

docker compose exec app php artisan make:seeder BookSeeder

database/seeders/BookSeeder.php:

<?php

namespace Database\Seeders;

use App\Models\Book;
use Illuminate\Database\Seeder;

class BookSeeder extends Seeder
{
    public function run(): void
    {
        Book::query()->insert([
            [
                'title' => 'Laravelの教科書',
                'author' => 'Sato',
                'published_year' => 2024,
                'created_at' => now(),
                'updated_at' => now(),
            ],
            [
                'title' => '実践PHPアプリ設計',
                'author' => 'Suzuki',
                'published_year' => 2025,
                'created_at' => now(),
                'updated_at' => now(),
            ],
        ]);
    }
}

ここでは 2 件の固定データをまとめて入れるため insert を使用。
insert は Eloquent の $fillable チェックを通らず、created_at / updated_at も自動では入らないため、その 2 つは明示しています。

Laravel 13 の create-project では database/database.sqlite と初回 migration が用意されるため、ここではそのまま migration -> seed の順に進めます。

順番は migration -> seed です。

docker compose exec app php artisan migrate
docker compose exec app php artisan db:seed --class=BookSeeder

Seeder を何度も実行すると同じ行が増える点には注意。
入れ直したいときは docker compose exec app php artisan migrate:fresh を使ってテーブルを作り直してから、もう一度 db:seed を流してください。

Laravel 13 の新規アプリは SQLite 前提で始めやすく、create-project 直後の状態からそのまま一覧ページの導線へ進めます。

7. 一覧ページを確認しながら役割を整理する

最後は、ルートと画面の確認。

docker compose exec app php artisan route:list

/BookController@index に向いていれば、ルーティングはつながっています。
ブラウザで http://localhost:8000 を開くと、2 件の本が並んだ一覧ページになるはずです。

本一覧ページの表示

ここで見えている 4 つの役割は次のとおりです。

  • Route: / へ来たアクセスを BookController@index へ渡す
  • Controller: Book モデルから一覧を取得し、View へ渡す
  • Model: books テーブルを Eloquent で扱う
  • View: 受け取った一覧を HTML として表示する

画面が空のままなら、次の順番で見ると切り分けやすくなります。

  1. docker compose exec app php artisan migrate が成功しているか
  2. docker compose exec app php artisan db:seed --class=BookSeeder を実行したか
  3. BookControllerBook::query()->orderBy('id')->get() が本文どおりか

8. よくある詰まりと次の一歩

docker compose up -d が通らないとき:

docker compose logs app

artisan や追加クラスが見つからないとき:

docker compose exec app composer dump-autoload

よくある詰まりは次の 4 つです。

  • 8000 番ポートが使用中
    • compose.yml の左側を 8001:8000 などへ変更する
  • View [books.index] not found.
    • resources/views/books/index.blade.php の配置を確認する
  • migration ファイル名が本文と違う
    • 先頭 timestamp は毎回変わるので、*_create_books_table.php を編集すればよい
  • データが表示されない
    • migratedb:seed の順で実行できているか確認する

ここまで進めば、Laravel の最初の 4 要素は一度つながりました。
次に広げるなら、フォーム作成 -> バリデーション -> 作成 / 編集 / 削除の順で進めると、CRUD の流れが自然に見えてきます。

シリーズ 1/16

このシリーズ

Laravelの基本を最初から通す

  1. 1. Laravel入門(Route / Controller / View / Model 最小構成) 現在の記事
  2. 2. Laravelで最小CRUDを作る(一覧 / 作成 / 編集 / 削除)
  3. 3. Laravelで品質ゲートを敷く(PHPUnit / Larastan / Pint / GitHub Actions)
  4. 4. Laravelで認証を足す(Breeze 最小導入)
  5. 5. Laravelで認可を入れる(Policyで自分の本だけ編集できるようにする)
  6. 6. LaravelでQueueを始める(database queue + worker 最小構成)
  7. 7. Laravelでスケジューラを動かす(Command + Scheduler 最小構成)
  8. 8. Laravelでファイルアップロードを扱う(Storage + validation)
  9. 9. Laravelでリレーションを扱う(User / Book / Category の基本)
  10. 10. Laravelで検索・並び替え・ページネーション付き一覧を作る
  11. 11. LaravelでLivewireを始める
  12. 12. LaravelでLivewire一覧画面を作る(検索・並び替え・ページネーション)
  13. 13. LaravelでSanctum認証APIを作る
  14. 14. LaravelでBlade / Livewire / Inertia をどう使い分けるか
  15. 15. LaravelでInertia + Vue.js を始める
  16. 16. LaravelでInertia + React を始める