【4月学習振り返り】LaravelのMVCの全体像が見えてきた月
はじめに
前回の投稿から1ヶ月以上空いてしまいましたが、4月の学習を振り返ります。
4月は大きく以下の3つに取り組みました。
1. 過去の学習内容をブログ化
1月・2月の学習メモを整理しながら、Qiitaの学習記録を4月中に2本公開しました。
- 1月の学習:https://qiita.com/11eleven/items/be7adbd4b5dde77a1419
- 2月の学習:https://qiita.com/11eleven/items/adb3c3253a63f332f4d9
- 3月の学習:https://qiita.com/11eleven/items/dfd1aec0009ebd27849f
気づいたこと: 学習した内容をブログにまとめることで、「この月に自分はここまで進めた」という事実ベースの自己評価ができるようになりました。振り返りは面倒ですが、やると自信につながるのでこれからも継続していきます。
2. LaravelのMVCフローをコード読解で整理
先輩がGitHubに用意してくれた学習用Webアプリ(職業管理アプリ)をクローンし、ローカル環境でセットアップ。穴埋め形式でコードを実装しながら、追加機能(CSV・TSV出力)も実装しました。
これまでLaravelは「MVCという流れで処理がされている」くらいの理解しかなかったのですが、コードを読んで書くことで全体像がかなり見えてきました。
理解できた主なポイント
AppServiceProvider
app/Providers/AppServiceProvider.php にLaravel全体の初期設定を書けることを知りました。カスタムディレクティブもここで定義できるため、今後自作のディレクティブでView作成も試してみたいと思います。
CSRFチェック
POST・PUT・PATCH・DELETEはCSRFチェックが必須であることを、あえて @csrf をコメントアウトして 419エラーを実際に出力させることで 体感して理解しました。
Controller・Model・web.phpの役割
| ファイル | 主な役割 |
|---|---|
web.php |
ルーティング定義 |
Controller |
return でViewを返す(echo は使わない) |
Model |
カラムへの代入許可設定、DBのリレーション定義 |
ポイント: Controllerでは echo で直接出力するのではなく、return でViewを返す のが基本ルールです。最初は混同しやすいので注意。
formタグとDELETEメソッド
HTMLの <form> タグはGETとPOSTしか送れません。ただしLaravelでは @method('DELETE') を書くことでDELETEリクエストとして扱えます。
<form action="/items/{{ $item->id }}" method="POST">
@csrf
@method('DELETE')
<button type="submit">削除</button>
</form>
Bladeディレクティブ
| ディレクティブ | 役割 |
|---|---|
@extends |
親レイアウトを継承する宣言 |
@section / @endsection
|
親レイアウトの枠に流し込む内容を定義 |
@yield |
子の内容を入れる枠を作成 |
@include |
別のBladeファイルを差し込む |
@foreach / @endforeach
|
複数データをHTMLに変換 |
@forelse |
@foreach に「空の場合の処理」を加えたもの |
@csrf |
フォーム送信時にCSRFトークンを自動埋め込み |
@method('DELETE') |
formタグのメソッドをDELETEとしてLaravelに伝える |
混同しやすいポイント: @extends は子が親を継承する方向、@include は親が子を取り込む方向と、呼び出しの向きが逆になっています。
3. FoodLog(食事管理アプリ)の設計見直し
3月から開発を続けている自作のPHP製Webアプリです。4月は機能追加よりコードの設計を見直す作業が中心でした。
単一責任の原則に基づくクラス分割
それまで1ファイルにすべての処理をべた書きしていたのを、単一責任の原則に基づいて名前空間を活用しながら個別クラスに分割しました。
Loggerクラスの作成
デバッグ用に操作ログをファイルへ残す Logger クラスを「関心の分離」という設計思想にのっとって作成しました。PHPのエスケープシーケンス \n で改行しながらログを追記する仕組みです。
キャストと型宣言の違い
(int)$post['id'] // キャスト:文字列 → 整数に「変換」する
int $post // 型宣言:整数しか受け取らないという「バリア」を張る
キャストは変換、型宣言はバリア と覚えると混乱しなくなりました。
インターフェースの実装
MealRepository.php にインターフェースを実装しました。
インターフェースは「何をするか」だけを定義し、中身の処理は書かない仕組みです。たとえばDBをMySQLからPostgreSQLに切り替えたい場合に、実装クラスだけ差し替えれば済むようにするための設計です。
// インターフェース(何をするかだけ定義)
interface MealRepositoryInterface {
public function getAll(): array;
public function create(array $data): void;
}
// 実装クラス(実際の処理を書く)
class MealRepository implements MealRepositoryInterface {
public function getAll(): array { /* MySQLの処理 */ }
public function create(array $data): void { /* MySQLの処理 */ }
}
名前空間(namespace)の注意点
クラスを個別ファイルに分けるにあたって、名前空間(namespace)のはまりポイントを整理しました。
namespace App\Repository;
// ❌ これだとPDOクラスが見つからないエラーになる
$pdo = new PDO(...);
// ✅ グローバル空間を明示する必要がある
$pdo = new \PDO(...);
// または
use PDO;
$pdo = new PDO(...);
ポイント: 独自の namespace を定義したファイル内で PDO などのPHP組み込みクラスを使う場合は、\PDO または use PDO が必要です。また、インターフェースを連携しているクラスに名前空間を定義する場合は、インターフェース側にも同じ名前空間の定義が必要になります。
CSSの疑似クラス・疑似要素
FoodLogのUIに疑似クラス・疑似要素を取り入れました。
ユーザー操作に反応する疑似クラス
| セレクタ | タイミング |
|---|---|
:hover |
マウスが乗ったとき |
:focus |
フォーカスしているとき |
:active |
クリック中 |
位置で絞り込む疑似クラス
| セレクタ | 対象 |
|---|---|
:first-child |
最初の要素 |
:last-child |
最後の要素 |
:nth-child(n) |
n番目の要素 |
疑似要素
| セレクタ | 役割 |
|---|---|
::before / ::after
|
要素の直前・直後に仮想の子要素を生成(content: "" が必須) |
::placeholder |
inputのプレースホルダーをカスタマイズ |
::selection |
テキスト選択時の色をカスタマイズ |
まとめと今後の課題
4月は「読む」と「書く」を交互に繰り返した1ヶ月でした。
LaravelのMVCの全体像が見えてきて、「このコードが何をしているか」を追えるようになってきたのは大きな進歩だと感じています。ゼロから自分で書けるレベルにはまだ達していませんが、AIが生成したコードを模写しながら理解を整理するというアプローチで確実に定着が進んでいます。
残っている課題
これからは、より多くのコードに手を出すより触れたコードを深掘りして自分で考えて手を動かしながら定着させることを意識していきたいと思います。

