タイトルで釣る
はじめに
この記事は Laravel Advent Calendar 2019 の24日目の記事です
この記事を書こうと思った理由
ネタが思いつかなかった
Laravelを業務で触れて1年が経とうかというのに未だLaravelの基本的な機能を理解しているか
と言われたら首が引きちぎれる勢いで首を横に振ってしまいます。
始めた当初は、実行の流れ(ライフサイクル)も含めてふぁさーど??さーびすこんてな??だったので、
きっと同じように理解しないまま使ってる(または葬られた)人もいるだろうと思い書きました。
そもそもLaravel使うメリットは
シンプルなMVC構造かつORMなどの機能だけでなく、
強力なルーティングフィルターや柔軟なオートローダーなどをサポートしており、
開発者は設計を意識せずに開発ができる。
↑とりあえずよく目にするやつ
Laravelが実行されるまでの流れってどうなってるの
LaravelのアプリケーションではURLにアクセスした時にエントリポイント(public/index.php
)が参照される仕組みになっており、
その中でオートロードファイルの読み込みアプリケーションの設定・実行が行われています。
エントリポイントの中身(public/index.php
)
実行の流れ(ライフサイクル)
実行までのフローを見るとこんな感じになっていて、
ユーザーがURLにアクセスしてから① ~ ⑦までの流れで実行されています。
MVC(Model View Controller)
上記の実行フローの画像⑥の部分でコントローラーを起点にモデルやビューの参照が行われている
ルーティング
先ほどの実行フローの画像④でルータでは、URLとコントローラーを紐付けています。
どう言う事??ってなるので画像で説明(文字で説明できないボンクラ)
上記画像ではフローを端折ってますが、左のユーザーがhttp://test/welcome
と言うURLにアクセスした時に、
エントリーポイントからルータ(routes/web.php
)が呼び出され、URLの最後のパス welcom
と紐付くコントローラーを検出します。
どうやって検出しているかというと下記の様に設定することでLaravelが認識することが出来ます。
...と言う風な流れでURLとコントローラーが紐づけられ、後はコントローラーを起点にModelから値を取得してViewに渡せば先ほどのMVCの画像と繋がりユーザーにページが表示される様になると言うわけです。
画像は全部LTした時の使い回し
追記
この記事書いた後にたまたま見つけた記事が詳しく書いてて、良記事だったので置いとく(最初から知りたかった)
少し初学者には難しいかもなので、上記を理解してみると良いかも。。
[Laravel] ドキュメントの概念について調べて見た
目にしただけで睡魔に襲われる機能(多分自分だけ)
- DI(依存性の注入)
- サービスコンテナ(DIコンテナ)
- サービスプロバイダ
- ファサード
- ミドルウェア
僕の知識と文才では知識が0の人に100教えるのは無理(と言うか自分がそこまで理解してない)なので
雰囲気だけ伝われば幸い。。
この辺に関しては良記事が溢れているので、触りだけ説明して後は記事に横流しという他力本願スタイルでいかせてもらう
DI(依存性の注入)
Laravelを調べていると良く目にするDI(依存性の注入)
とDIコンテナ(サービスコンテナ)
という言葉
実はLaravelに限った機能という訳ではなく、プログラムの世界では幅広く使われています。
だからDIって何だよ!!ってなってる方はどうか怒りをお沈めください。
DIというのは簡単に言うと クラスの内部でインスタンス生成(new)するのではなく、外部で用意して注入してね と言う事です。
めっちゃ噛み砕いて言うとクラスの中でnewすんなってこと。(多分叩かれる)
じゃあ外部でインスタンスを用意するってどう言うこと??ってなると思う。
コードの例で見てみましょう。
ユーザーの携帯を鳴らすと言う簡単な処理を実行しているこの処理を...
<?php
class User
{
protected $phone;
public function __construct()
{
$this->phone = new Phone();
}
public function UserCallPhone()
{
$this->phone->call();
}
}
class Phone
{
public function call()
{
return "プルプル...";
}
}
$user = new User();
下記の様に外部(クラス外)でPhoneクラスをインスタンス化して、Userクラスに注入すれば外部からインスタンスを用意した。つまり依存性の注入が出来たということになる。
<?php
class User
{
protected $phone;
public function __construct(Phone $phone)
{
$this->phone = $phone;
}
public function UserCallPhone()
{
$this->phone->call();
}
}
class Phone
{
public function call()
{
return "プルプル...";
}
}
// ここでPhoneクラスをインスタンス化
$phone = new Phone();
// Phoneクラスのインスタンスを引数に渡す
$user = new User($phone);
これでUserクラスはPhoneクラスとの疎結合に成功しました。
(インターフェースに分けないと本当の意味で依存関係を解決したとは言わないかも。。)
このクラス同士の依存を無くして疎結合にしようね。ってのがDI。
参考
この記事凄く分かりやすいのでぜひ
LaravelのDIコンテナはどう使われているのか
サービスコンテナ(DIコンテナ)
上記のDI(依存性の注入)で何と無くDIは理解したけどサービスコンテナってなんだよ!!って方、ちゃんと説明します。
実はLaravelを学習する上で結構大事な要素だったりします。
例によって、簡単に説明すると依存関係を解決するために行なっていた外部からの注入(上記
DI参考)をまとめて担ってくれるのがサービスコンテナです。
噛み砕くと(また怒られる)サービスコンテナは下記の様な解釈でいいと思います。
サービス
=> インスタンス化(new)
コンテナ
=> 入れ物
再度、先ほどのUserクラスとPhoneクラスのDIをサービスコンテナを使って、再現してみます。
class User
{
protected $phone;
public function __construct()
{
// インスタンスの生成方法を登録する
app()->bind('Phone', function(){
return new Phone();
});
// サービスコンテナが生成したインスタンスを取得
$this->phone = app()->make('Phone');
}
public function UserCallPhone()
{
$this->phone->call();
}
}
class Phone
{
public function call()
{
return "プルプルプル...";
}
}
$user = new User();
先ほどは外部でPhoneクラスをインスタンス化して、Userクラスに外部から注入していましたが、
上記では__construct()内で何やらごにょごにょしている様です。
バインド(bind)
bind()にクラス名を渡してそのインスタンスの生成方法をサービスコンテナに登録する
app()->bind('Phone', function(){
return new Phone();
});
リゾルブ(resolve)
指定されたインスタンスをサービスコンテナが生成したインスタンスを取得
サービスコンテナが生成したインスタンスを返すことを解決(resolve)という
$phone = app()->make('Phone');
各コードの説明である通りbindでインスタンス生成方法をサービスコンテナに登録して、
サービスコンテナからインスタンスを取得することでDIを実現している。
つまりPhoneクラスのインスタンス(new)をサービスコンテナが代わりに作って渡してくれている。
さらにサービスコンテナでは下記の様にも書けます!!
この様なやり方をメソッドインジェクション(この場合コンストラクタなのでコンストラクタインジェクション)と言います。
// Phoneクラスのインスタンスを$phoneに渡している
public function __construct(Phone $phone)
{
$this->phone = $phone;
}
便利や....。
サービスプロバイダ
名前が似ているのでサービスプロバイダとサービスコンテナ何が違うの??となっている方もいると思いますので説明。
サービスプロバイダとはフレームワークやアプリケーションに含まれるサービス(機能)の初期処理を行う目的で用意されています。
Laravelではサービス(機能)毎に初期処理を定義して実行する仕組みがあり、
その仕組みや実際に初期処理の実装を行うクラスのことをサービスプロバイダ
と呼びます。
サービス
=> 機能
プロパイダー
=> 供給者
つまり機能(サービス)を供給する(プロバイド)クラスと言えます。
文章だけではあまりイメージ出来ないと思いますが、先ほどのサービスコンテナで利用したbind
はControllerに直接書かずに、
サービスプロバイダに切り分けて定義するって事だけ分かってればとりあえず良いかなと個人的には思ってます
実際のサービスコンテナの例
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class PhoneServiceProvider extends ServiceProvider
{
public function register()
{
app()->bind('Phone', function(){
return new Phone();
});
}
public function boot()
{
//
}
}
register()とboot()というメソッドが用意されていますが、こちらは実行されるタイミングの違いです。
ファサード
ファサードとはLaravelで用意されている独自クラスのメソッドをどこでも呼び出して使用できる様にした機能の事です。
これだけだとピンとこないかもしれませんが、ルーティングを設定するときに無意識に使っているはずです。
Route::get('/', 'HomeController@index');
Route::get
の部分が正にファサードです。
ここでいくつか疑問があると思います。一つずつ説明しましょう。
-
Q. 結局ファサードって何
- A. 処理をフレームワークに肩代わりさせて、手軽に使える様に出来る機能(めっちゃ噛み砕くと)
-
Q. 何でuseもパスもなしでこんな簡潔に書けるの??
- A.
config/app.php
でエイリアスを設定しているから
- A.
'aliases' => [
'Route' => Illuminate\Support\Facades\Route::class,
];
Laravelで用意された標準機能だけでなく、自作で作って設定することも可能です。
参考
(Laravel第6回目)ファサード(Facade)からサービスコンテナを学ぶ
Laravelファサードの作り方からその構造まで徹底解説入門
ミドルウェア
インフラ界隈だとOSとアプリケーション間の中間的な役割を担っている機能のことだが、
LaravelではHTTPリクエストをフィルタリングする際などのメカニズムとして用意されている。
(中間という意味では一緒)
ここで先ほどの実行のフロー(ライフサイクル)の画像を再度貼ります。
下記画像の⑤ミドルウェアを見ての通り、④ルーターから⑤ミドルウェアが実行され、その後に⑥のコントローラーを参照しているのが分かります。
しかし、画像を良く見てみると矢印の通り⑥→⑤→④と処理が戻っているのが分かると思います。
この通り、ミドルウェアではコントローラーの呼び出し前と呼び出し後にミドルウェアに設定された処理を行うことが出来ます。(と言えば語弊が生まれるかもしれないが)
(実行の流れ画像再添付)
コントローラーの前後に設定出来るのは分かったけど具体的に何が出来るの?という人もいると思います。
Laravelでログイン認証を実装した事がある人であれば何となく分かると思いますが、実はこのミドルウェアを使って、ユーザが認証済みかどうかの確認を影で行なっています。
それだけではなく、バリデーションやコンテンツの置換など様々な機能が用意されています。
Laravelの素敵なところは上記の様なデフォルト機能だけでなく、自分で簡単にミドルウェアを自作してコントローラーの前後に設定が出来るところです。
随時追加していきます(時間がなかった)
最後に
**Laravel完全に理解した()**状態にステップアップできたでしょうか。
結構記事によって説明が異なってたりするので自分の知識も間違ってる箇所あるかと思います。。
誤りに気付いた方はマサカリと思わず編集リクエストまたは指摘していただけると幸いです。