既存の Laravel プロジェクトを引き継ぐことになり、クローンしたはいいもののファイルが多すぎてどこから開けばいいのか分からない、という状態になりました。
上司にコードリーディング会を開いてもらい、プロジェクト全体を知るための Docker まわりと、Laravel の処理を追うための routes → コントローラ → Bladeという2段階に分けて教わりました。これが分かってから急に読めるようになったので、その日に教わったことをまとめておきます。
Laravel を触り始めたばかりで、既存プロジェクトの全体像が掴めていない人向けです。
いきなり src を開かず、まず Docker まわりを見る
最初にやりがちなのが、src の中を片っ端から開いて迷子になることでした。先に見るべきは、その下に置いてあるアプリがどんな環境で動いているかのほうです。
ルート直下はだいたいこんな構成になっています。
.
├── docker-compose.yml
├── Dockerfile
└── src/ ← Laravel 本体
docker-compose.yml:build と image の違いだけ押さえる
docker-compose.yml は、複数のコンテナ(app や db)をまとめて定義して、docker compose up 一発で立ち上げるための設定ファイルです。
読むときに一番効くのが、サービスごとの build と image の違いでした。
services:
app:
build: . # ← Dockerfile をビルドしてイメージを作る
# 省略
db:
image: mysql:8.0 # ← ビルドせず、既成のイメージをそのまま使う
# 省略
-
build… その場でDockerfileを読んでイメージを作る。今回のプロジェクトでは、PHP のバージョンや拡張モジュールなど、案件固有の設定が必要なアプリ本体がこっち -
image… 公開されているイメージをダウンロードして使う。今回の MySQL は独自ビルドせず、既成のイメージを使っていた
読む立場からすると、これが分かるだけで作業が減ります。build と書いてあるサービスは Dockerfile を追い、image のサービスは指定されたイメージと Compose 側の設定を確認すればよいからです。
Dockerfile:app の中身が書いてあるだけ
Dockerfile は、app コンテナの中身(実行環境)を定義したファイルです。
FROM php:8.2-fpm
# 必要な PHP 拡張を入れる
RUN docker-php-ext-install pdo_mysql
# 省略
今回の Dockerfile では、冒頭の FROM を見ると、このアプリが PHP 8.2 をベースに動くことが分かりました。PHP のバージョンを確認したいときは、まずここを見るのが早いです。
src に artisan があったら Laravel
src を開いて、まず目印になるのが artisan というファイルでした。
src/
├── artisan ← これがあったら Laravel
├── composer.json
├── app/
├── routes/
└── resources/
artisan は Laravel のコマンドラインツールで、マイグレーションやキャッシュクリアをここから実行します。
php artisan migrate
php artisan route:list
ちなみに php artisan route:list はルーティングの一覧を表示するコマンドで、後述の「routes から読む」をコマンド側からやるようなものです。ファイルを開く前にこれを叩くと全体像が掴めます。
vendor が Git に入っていないのは正常
クローンした直後に vendor フォルダが無くて「ファイルが足りないのでは」と一瞬焦りましたが、これが正常でした。
-
vendor…composer.jsonに書かれた依存ライブラリのインストール先。composer installで生成される -
node_modules… フロント側の同じもの。package.jsonからインストールされる
どちらも**.gitignore に入れて Git 管理しない**のが基本です。理由はファイル数と容量が膨大だからで、復元に必要な情報は composer.json / composer.lock に全部あるので、各自が自分の環境で入れれば足ります。
# クローン直後はこれをやらないと動かない
composer install
npm install
裏を返すと、今回のプロジェクトはクローンしただけでは動かず、最初に依存ライブラリのインストールが必要ということでもあります。ここは最初に踏んでおくと無駄に悩まずに済みます。
本体は routes から読む
環境が分かったら、いよいよアプリ側です。結論として、読み始めの入口は routes でした。
今回追った画面では、「どの URL が、どのクラスのどのメソッドに対応するか」が routes に書かれていました。ここを見ると、目的の画面の処理をどこから追えばよいか分かります。
たとえば、次のようなルートがあったとします。
use App\Http\Controllers\PostController;
Route::get('/posts', [PostController::class, 'index']);
この1行で「/posts にアクセスされたら PostController の index() が動く」と読めます。あとはそのクラスへ飛ぶだけです。
PHP Intelephense を入れておく
地味ですが効果が大きかったのがこれです。VS Code に PHP Intelephense を入れておくと、クラス名やメソッド名を Cmd+クリックで定義元にジャンプできます。
コードリーディングでは飛び先を探すだけでも時間がかかるので、定義元へそのまま移動できるだけでかなり楽になりました。
クラスの冒頭に並んでいる呪文の意味
コントローラを開くと、処理の前に見慣れない記述が並んでいます。ここで止まりがちだったので、意味を整理しておきます。
namespace App\Http\Controllers; // ①
use App\Models\Post; // ②
class PostController extends Controller // ③
{
public function __construct(...) // ④
{
// 省略
}
}
① namespace … そのファイルが置かれているディレクトリ構造に対応する名前空間。「このディレクトリ配下のクラスですよ」という宣言で、同じクラス名がぶつかるのを防ぎます。ディレクトリと対応しているので、名前空間を見ればファイルの場所が分かります。
② use … 「このクラスを使いますよ」という宣言。冒頭でフルパスを書いておくことで、以降は Post のようにクラス名だけで書けます(パスの省略)。
③ extends … 継承。親クラス(ここでは Controller)の機能を引き継いだ上で、独自の処理を足します。
④ __construct … コンストラクタ。インスタンスが作られたときに最初に走る初期化処理です。使うサービスやリポジトリの受け取りをここでやっていることが多いので、「このクラスが何に依存しているか」を見る場所でもあります。
return view() からビューへ飛ぶ
今回追った一覧画面では、コントローラのメソッドがこの形で終わっていました。
public function index()
{
$posts = Post::all();
return view('index', compact('posts'));
}
return view(...) は**「画面(ビュー)を返す」**という意味です。ここの引数2つが読めれば、次に開くファイルが決まります。
-
第1引数
'index'… 表示するビューの名前。resources/views/index.blade.phpを指します -
第2引数
compact('posts')… ビューに渡す変数。compactは変数名を文字列で並べると['posts' => $posts]という配列を作ってくれる PHP の関数です
つまり compact('posts') と書いておくと、Blade 側で $posts がそのまま使えます。
@if ($posts->isEmpty())
<p>投稿がありません</p>
@else
@foreach ($posts as $post)
<li>{{ $post->title }}</li>
@endforeach
@endif
compact に書いた変数名が、そのままテンプレート内の変数名になるので、ここの対応さえ意識しておけば「この $posts はどこから来たの?」で迷わなくなります。
結局どの順番で追えばいいのか
一連の流れを図にするとこうなります。
読むときの手順としては、こうなります。
-
routesで URL からコントローラ/メソッドを特定する -
コントローラを開いて、データの取得と加工を読む(
__constructの依存もここで確認) -
return view('~', compact('~'))の行から、対応するresources/views/~.blade.phpへ飛ぶ - Blade で、渡ってきた変数がどう表示に使われているかを見る
まとめ
-
docker-compose.ymlのbuildかimageかを見ると、Dockerfileを追うサービスと、指定されたイメージを確認するサービスが分かる -
vendor/node_modulesが無いのは正常。今回のプロジェクトでは、まずcomposer installとnpm installが必要 - アプリ側は
routesが入口。view()の第1引数が Blade のファイル名、compactがそこに渡る変数
既存の Laravel プロジェクトを開いて途方に暮れたら、まず Docker まわりで実行環境を確認する。そのあと、routes から気になる URL のコントローラをたどる。自分はこの順番が分かって、ようやく迷子から抜け出せました。
php artisan route:list が実行できる環境なら、ルーティングの一覧を出してから気になる URL を探すのも分かりやすいです。
参考
関連記事
- 初めてのAI駆動開発。勤怠管理アプリを1ヶ月で本番公開した全8ステップ … 開発エンジニアになってから、初めてアプリを本番公開するまでにやったことをまとめています
- FastAPI で「Summary 型」を作る — 一覧APIでユーザー情報を返すときの共通モデル … バックエンドのコードを読みながら、共通のレスポンスモデルを作ったときの話です
告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。
みなさまからのご応募をお待ちしております。

