CodeIgniterのコントローラを肥大化させない!初心者でもわかる「スリムな設計」のコツ
生徒
「CodeIgniterでアプリを作っているのですが、コントローラのファイルがどんどん長くなって、どこに何が書いてあるか分からなくなってしまいました…。」
先生
「それはプログラミング初心者が最初によくぶつかる壁ですね。コントローラに何でもかんでも書きすぎてしまうことを『肥大化』と呼びます。」
生徒
「どうすればスッキリ整理できるんでしょうか?パソコンも初心者なので、簡単な例えで教えてほしいです!」
先生
「分かりました。料理店に例えると、コントローラは『注文を受ける店員さん』です。店員さんが料理まで作り始めると大変ですよね?役割を分担するコツを学んでいきましょう!」
1. コントローラとは?役割を再確認しよう
PHPの人気フレームワークであるCodeIgniter(コードイグナイター)には、「MVC(エムブイシー)」という仕組みがあります。これは、プログラムの役割を3つのチームに分ける考え方です。
- M(モデル):データの処理担当(料理を作る人)
- V(ビュー):見た目の表示担当(お皿や盛り付け)
- C(コントローラ):司令塔・つなぎ役担当(注文を受ける店員さん)
初心者のうちは、この「コントローラ」の中に、計算式やデータベースとのやり取りをすべて書いてしまいがちです。しかし、本来のコントローラの仕事は「ユーザーからの入力を受け取って、モデルにお願いして、結果をビューに渡す」という橋渡しだけにするのが理想です。
2. なぜコントローラが太ってしまうのか?(肥大化の原因)
プログラムが「肥大化」する、つまりコードの行数が何百行、何千行と増えてしまう最大の原因は、「コントローラに計算や複雑なルールを書きすぎている」ことです。
例えば、ブログの記事を投稿する機能を考えてみましょう。 「文字数は足りているか?」「禁止用語は入っていないか?」「画像は正しい形式か?」といったチェック(バリデーションといいます)や、「データベースへの保存」「完了メールの送信」といった作業をすべてコントローラに書くと、あっという間にファイルがパンパンになってしまいます。これを防ぐためには、「ロジック(仕組み)」を外に追い出す必要があります。
3. ロジックをモデル(Model)へ移動させよう
CodeIgniterにおいて、データベースに関わる計算や処理は、できるだけ「Model(モデル)」に書くようにしましょう。これを「Fat Model, Skinny Controller(太ったモデル、痩せたコントローラ)」と呼び、良い設計の合言葉とされています。
以下に、悪い例(コントローラが太っている状態)のイメージを紹介します。
// 悪い例:コントローラの中で全部やってしまっている
public function register() {
$name = $this->request->getPost('name');
// データベースへの保存処理をコントローラに直接書くと肥大化の原因に!
$db = \Config\Database::connect();
$sql = "INSERT INTO users (name) VALUES (" . $db->escape($name) . ")";
$db->query($sql);
return view('success_view');
}
このようにコントローラに直接データベースの操作を書くのではなく、専用のモデルを作って、そちらに「保存してね」と頼むように書き換えるのがスリム化への第一歩です。
4. バリデーション(入力チェック)を外部化する
「名前が未入力ではないか?」「メールアドレスの形式が正しいか?」といったチェックをコントローラの中に書くと、同じようなコードが何度も登場してしまいます。CodeIgniterには、これらを自動で処理する機能があります。
チェックのルールを別ファイル(設定ファイル)にまとめたり、専用のクラスを作ったりすることで、コントローラの記述をたった一行に減らすことができます。店員さんが「お客様の注文が正しいか」をいちいち細かくチェックするマニュアルを暗記するのではなく、チェックリスト(外部ファイル)を見て判断するイメージです。
5. 共通の処理は「ライブラリ」や「ヘルパー」を活用
どの画面でも使うような共通の処理(例:日付の形式を変換する、ログインしているか確認するなど)は、コントローラに書くのではなく、「ヘルパー(Helper)」や「ライブラリ(Library)」という場所にまとめます。
例えば、消費税の計算をする処理が必要な場合、それをコントローラに書くのではなく、以下のように共通の関数として定義しておくと便利です。
// 共通ヘルパーのイメージ
function calculate_tax($price) {
// 10%の消費税を計算して返す
return $price * 1.1;
}
これを用意しておけば、どのコントローラからも calculate_tax(1000) と呼び出すだけで済むようになり、コントローラが非常にスッキリします。
6. 条件分岐をシンプルにするテクニック
コントローラの中で「もしAならこれ、Bならこれ、Cなら…」と if 文が重なりまくると、読むのが嫌になってしまいます。そんなときは、複雑な条件判定そのものをモデル側に持たせるか、早期リターンという手法を使います。
早期リターンとは、ダメな場合はすぐに処理を終わらせる書き方です。これにより、コードの階層(インデント)が深くならず、読みやすくなります。
// 早期リターンを使ったスッキリした書き方
public function update_profile() {
// ログインしていなければ、即座に終了してログイン画面へ
if (!$this->is_logged_in()) {
return redirect()->to('/login');
}
// ここからはログインしている人だけの処理(ifのネストが深くならない!)
$this->userModel->save($this->request->getPost());
return view('profile_updated');
}
7. サービス層(Service Layer)の導入を検討する
さらに大規模なアプリを作るようになると、モデルだけでも足りなくなることがあります。そんなときは「サービス(Service)」という新しい担当者を雇うことを検討しましょう。
例えば「商品を注文する」という動作には、「在庫を減らす」「ポイントを付与する」「注文確認メールを送る」といった複数の作業が伴います。これらを一つの「注文サービス」というクラスにまとめておけば、コントローラは「注文サービスを実行して!」と一言命じるだけでよくなります。
// サービス層を使ったスリムなコントローラの例
public function checkout() {
$orderService = new OrderService();
// 複雑な一連の処理はサービスの中で実行される
$result = $orderService->processOrder($this->request->getPost());
if ($result) {
return view('order_success');
} else {
return view('order_error');
}
}
8. 良い設計は「変更に強い」アプリを作る
なぜここまでしてコントローラをスリムにする必要があるのでしょうか?それは、「後からの修正が楽になるから」です。プログラムの世界では、一度作って終わりということはありません。「やっぱり消費税を15%にしたい」「メールの文面を変えたい」といった変更が必ず発生します。
その際、コントローラがパンパンだと、どこを直せばいいか分からず、一箇所直すと別の場所が壊れるという悪夢が起こります。役割をしっかり分けておけば、モデルだけを直せばすべての画面に反映されるといった、スマートな管理が可能になります。初心者のうちから「店員さん(コントローラ)に無理をさせない」設計を意識して、楽しく開発を続けていきましょう!