はじめに
この記事はLaravelを使用するプロジェクトに携わり始めて1年程度経った筆者が、自分なりに理解したLaravelというフレームワークの基本です。
Laravel初学者の理解の助けになることを願い、本記事を書いています。
結論
さっそくですが、結論です。
Laravel とは MVCモデル を採用したフレームワークである。
これがすべてです。
ただ、これだと何のことかわからないと思うので簡単に解説します。
MVCモデル とは
結論
オブジェクト指向という設計思想を根底に持った設計パターンである
解説
MVCとは モデル(Model) 、 ビュー(View) 、コントローラー(Controller) という役割ごとに責務の分割を採用した設計パターンです。
それぞれ Laravel で該当する要素とその役割は下記の通り。
| MVC要素 | Laravel要素 | 役割 |
|---|---|---|
| コントローラー | コントローラークラス | ユーザーからのリクエストを受け取り、適切な処理依頼を発行し、レスポンスを返す |
| モデル | Eloquentモデル、サービスクラスやリポジトリクラス | コントローラーから発行された依頼に応じて適切なデータ処理を行う |
| ビュー | Bladeファイル | コントローラーからのレスポンスをもとにユーザーにデータを表示する |
つまり Laravel は MVCモデル を根底に、さらに責務の細分化を推奨するフレームワークです。
そして、結論でも述べた通り MVCモデルは オブジェクト指向 という設計思想に基づいています。
オブジェクト指向 とは
結論
クラス や オブジェクト といった概念を用いてコードを記述する設計思想である。
解説
WEB関連の言語から入ったプログラミング初学者にとってここは鬼門であると思っています。
自分はそうでした。
よく例えとして採用されるのが、車 と 車の設計図 というもの。
クラス とは定義しただけでは意味がなく、そのクラスを オブジェクト としてインスタンス化して始めてその役割を果たします。
つまり、例えに当てはめると 車 = オブジェクト であり 車の設計図 = クラス という関係性になり、インスタンス化は 設計図を基にした車の製造 にあたります。
ここまでは初学者であっても理解できるんじゃないかと思いますが、だから何?ということになると思います。
理解はできるけど、何の利点があってどういう時に使うの?
そうは思いませんか?自分はそうでした。
正直、実際に実装作業をやってみてコードの最適化という観点で開発に取り組んでみないと実感としてオブジェクト指向というものを理解できないと思います。
そこで、今回議題に挙げていた Laravel はこの理解の助けになると思います。
Laravel で理解する オブジェクト指向
さきほど Laravel の要素で挙げたコントローラーを例に話を進めようと思います。
一般的な Laravel での実装ではコントローラーは下記のように役割ごとに複数作成することが多いです。
| コントローラー名 | 役割 |
|---|---|
| UserController | ユーザーのデータに関するリクエストを受け付ける |
| BookController | 書籍のデータに関するリクエストを受け付ける |
これらをそれぞれ実装すると下記のようなものになると思います。
UserController
class UserController extends Controller
{
public function store(Request $request)
{
// 本来はここでバリデーションを行いますが省略
$user = User::create($request->all());
// レスポンスの形式を都度手書きしている
return response()->json([
'status' => 'success',
'data' => $user,
'message' => 'ユーザーを作成しました'
], 201);
}
}
BookController
class BookController extends Controller
{
public function store(Request $request)
{
$book = Book::create($request->all());
// UserControllerと同じ形式でレスポンスを返したい...
return response()->json([
'status' => 'success',
'data' => $book,
'message' => '書籍を登録しました'
], 201);
}
}
比較してみてもらえればわかると思いますが、return response()->json(...) の部分で同じような記述を繰り返していますよね?
同じような記述ってしたくないですよね?
もし「status キーを result という名前に変更したい」となった場合、すべてのコントローラーを書き直す必要が出てくるし嫌ですよね?
そこで、レスポンスの形式を生成する共通機能を実装したコントローラークラスを作成し、それらを上記のコントローラーに 継承 させます。
ここでは例として共通機能を実装したコントローラーを BaseController とします。
共通クラスの採用
共通クラス
BaseController
class BaseController extends Controller
{
/**
* 成功時のレスポンスを共通化するメソッド
* @param mixed $data 返却するデータ
* @param string $message クライアントへのメッセージ
* @param int $code HTTPステータスコード
* @return \Illuminate\Http\JsonResponse
*/
protected function sendSuccess($data, string $message = 'Success', int $code = 200)
{
return response()->json([
'status' => 'success',
'message' => $message,
'data' => $data,
], $code);
}
/**
* エラー時のレスポンスを共通化するメソッド
*/
protected function sendError(string $message, int $code = 400)
{
return response()->json([
'status' => 'error',
'message' => $message,
], $code);
}
}
この BaseController を継承することで、子クラス(各コントローラー)は「レスポンスの中身のデータ」を渡すことだけに集中できるようになります。
共通クラスを継承した子クラス
UserController
// BaseControllerを継承
class UserController extends BaseController
{
public function store(Request $request)
{
$user = User::create($request->all());
// 親クラスのメソッドを呼ぶだけで、統一された形式で返却できる
return $this->sendSuccess($user, 'ユーザーを作成しました', 201);
}
}
BookController
class BookController extends BaseController
{
public function store(Request $request)
{
$book = Book::create($request->all());
// こちらも同様に1行で完結
return $this->sendSuccess($book, '書籍を登録しました', 201);
}
}
どうですか? 各コントローラーから「JSONの形式をどうするか」という記述が消え、「何をするか」 というロジックだけが残って非常にスッキリしました。
これが クラスの継承 における大きな利点の一つです。
「共通の振る舞い」を親クラスに定義しておけば、子クラスはその恩恵を受けることができ、変更があった場合も親クラス一箇所を直すだけで済みます。
Laravel というフレームワーク自体も、このオブジェクト指向の仕組みの集合体で出来ているのです。
まとめ
いかがでしたでしょうか?
Laravel とは何か とか言いながら オブジェクト指向 についての解説になってしまいました。
ミスリードで申し訳ないですが、諸々の概念の理解の助けになれば嬉しいです。