Slide 1

Slide 1 text

Service Provider Service Container 2/16 Laravel JP Conference 前田 和人

Slide 2

Slide 2 text

こんな人におすすめ ■ MVCは何となくわかる ■ それ以外の機能はあまり知らない ■ サービスコンテナを使ったことがない ■ サービスコンテナで挫折した

Slide 3

Slide 3 text

このセッションの目標 ■ サービスコンテナをざっくり理解する ■ サービスコンテナに1つ目のサービスを結合する勇気が 出る

Slide 4

Slide 4 text

お話しないこと ■ サービスコンテナの細かい仕様・実装 ■ 豊富な実装例 ■ サービスディスカバリ

Slide 5

Slide 5 text

注意事項 ■ このセッションでは、理解することを最優先します ■ 場合によっては正確ではないことを記載している場合が あります

Slide 6

Slide 6 text

■ 時間の都合で削らせていただきます。すみません。 注意事項

Slide 7

Slide 7 text

注意事項 ■ 以下に資料があがってますの で、お手元で見ていただくこ とをおすすめします。 ■ https://speakerdeck.com/chi roruxx/serviceprovider- servicecontainer-ru-men

Slide 8

Slide 8 text

自己紹介 ■ 前田 和人 ■ @chiroruxxxx ■ 弁護士ドットコム株式会社

Slide 9

Slide 9 text

自己紹介 ■ 前田 和人 ■ @chiroruxxxx ■ 弁護士ドットコム株式会社

Slide 10

Slide 10 text

弁護士ドットコム

Slide 11

Slide 11 text

BUSINESS LAWYERS

Slide 12

Slide 12 text

本題

Slide 13

Slide 13 text

なぜサービスコンテナは難しいのか

Slide 14

Slide 14 text

なぜサービスコンテナは難しいのか サービス DI サービス コンテナ インター フェース 自動注入

Slide 15

Slide 15 text

なぜサービスコンテナは難しいのか サービス DI サービス コンテナ インター フェース 自動注入

Slide 16

Slide 16 text

DI サービス DI サービス コンテナ インター フェース 自動注入

Slide 17

Slide 17 text

ユースケース ■ 次のようなサービスクラス(コンポーネント)があるとし ます ■ SendGridに関する操作を行うサービス – SendGrindのコンタクトリストに ユーザを追加する – SendGridを使用してメールを送信する

Slide 18

Slide 18 text

SendGrid ■ クラウドベースのメール配信サービス ■ 送りたい内容をAPIで送るとメール送ってくれる ■ メールについて知らなくてもwebの知識でメールを扱え る

Slide 19

Slide 19 text

ユースケース ■ 次のようなサービスクラスがあるとします。 ■ SendGridに関する操作を行うサービス – SendGrindのコンタクトリストに ユーザを追加する – SendGridを使用してメールを送信する

Slide 20

Slide 20 text

サービスのコード class SendGridService { private $sendGrid; public function __construct() { $this->sendGrid = new SendGrid(config('services.sendgrid.key')); } public function saveUser(User $user): void { // コンタクトリストへの追加処理 } public function sendMail(Mail $mail): void { // メール送信処理 } }

Slide 21

Slide 21 text

ユースケース ■ 統計上の都合により、ユーザ側と管理者側でAPIキーを 分けることになりました

Slide 22

Slide 22 text

コードの状態 ■ 現状はサービスのコンストラクタにAPIキーをべた書き public function __construct() { $this->sendGrid = new SendGrid(config('services.sendgrid.key')); }

Slide 23

Slide 23 text

コードの状態 ■ UserSendGridクラスとAdminSendGridクラスに分け る・・・? – 設定の数だけクラスが増えていくの・・・? ■ apiSetterメソッドを作る・・・? – インスタンスの状態を管理しないといけなくなる ■ ⇒DIをしよう!

Slide 24

Slide 24 text

DIとは? ■ 何の略語かとか、日本語訳を載せると 途端に難しそうにきこえるアレ ■ DIとは、インスタンスの生成に必要な設定をコンストラ クタの引数で渡してあげること – 今回で言うと、SendGridクラス ■ インスタンスの設定を状況に合わせて指定できる

Slide 25

Slide 25 text

元のサービスのコード class SendGridService { private $sendGrid; public function __construct() { $this->sendGrid = new SendGrid(config('services.sendgrid.key')); } // …その他の処理 }

Slide 26

Slide 26 text

サービスのコード class SendGridService { private $sendGrid; public function __construct(SendGrid $sendGrid) { $this->sendGrid = $sendGrid; } // …その他の処理 }

Slide 27

Slide 27 text

サービスのコード class SendGridService { private $sendGrid; public function __construct(SendGrid $sendGrid) { $this->sendGrid = $sendGrid; } // …その他の処理 } 設定を受け取る

Slide 28

Slide 28 text

サービスのコード class SendGridService { private $sendGrid; public function __construct(SendGrid $sendGrid) { $this->sendGrid = $sendGrid; } // …その他の処理 } そのまま プロパティにする

Slide 29

Slide 29 text

元のコントローラのコード // sendgridのcontactに登録 $sendGridService = new SendGridService(); $sendGridService->saveUser($user);

Slide 30

Slide 30 text

適用後のコントローラのコード // sendgridのcontactに登録 $sendGrid = new SendGrid(config('services.sendgrid.user.key’)); $sendGridService = new SendGridService($sendGrid); $sendGridService->saveUser($user);

Slide 31

Slide 31 text

ユーザー側のコントローラのコード // sendgridのcontactに登録 $sendGrid = new SendGrid(config('services.sendgrid.user.key’)); $sendGridService = new SendGridService($sendGrid); $sendGridService->saveUser($user); 設定を生成

Slide 32

Slide 32 text

ユーザー側のコントローラのコード // sendgridのcontactに登録 $sendGrid = new SendGrid(config('services.sendgrid.user.key’)); $sendGridService = new SendGridService($sendGrid); $sendGridService->saveUser($user); 生成した設定を渡す

Slide 33

Slide 33 text

DIのまとめ ■ DIとは、インスタンスの生成に必要な設定を引数で渡し てあげること ■ 設定を外から渡すことで、インスタンスの設定を状況に 合わせて指定できる

Slide 34

Slide 34 text

サービス DI サービス コンテナ インター フェース 自動注入 サービスコンテナ サービスプロバイダ

Slide 35

Slide 35 text

コードの問題点① ■ メール関連の処理は色々なところで使われる ■ 毎回サービスを作成するのはコストがかかる $sendGrid = new SendGrid('services.sendgrid.user.key'); $sendGridService = new SendGridService($sendGrid);

Slide 36

Slide 36 text

コードの問題点② ■ DIを使うと、サービスを使う側でnewする回数が増える ■ 設定が3つや4つになったら・・・? $sendGrid = new SendGrid('services.sendgrid.user.key'); $sendGridService = new SendGridService($sendGrid);

Slide 37

Slide 37 text

コードの問題点② ■ newだらけ! ■ サービスの生成だけで、すごい幅をとる ■ 本当にやりたいことはサービスを生成した後にあるは ず・・・ $settingA = new SettingA(); $settingB = new SettingB(); $settingC = new SettingC(); $settingD = new SettingD(); $someService = new SomeService($settingA, $settingB, $settingC, $settingD);

Slide 38

Slide 38 text

コードの問題点 ■ まとめると・・・ ■ 各処理ごとにサービスを毎回つくりたくない – ⇒サービスをまとめて管理したい ■ サービスの生成をロジックに書きたくない – ⇒サービスの生成方法をまとめて管理したい

Slide 39

Slide 39 text

コードの問題点 ■ まとめると・・・ ■ 各処理ごとにサービスを毎回つくりたくない – ⇒サービスをまとめて管理したい – サービスコンテナ ■ サービスの生成をロジックに書きたくない – ⇒サービスの生成方法をまとめて管理したい – サービスプロバイダ

Slide 40

Slide 40 text

サービスコンテナとは? ■ サービスをまとめて管理するツール ■ 様々なサービスを入れられるグローバルな連想配列 ■ 例 key value sendgrid SendGridService ga GoogleAnalyticsService payment StripeService

Slide 41

Slide 41 text

サービスコンテナとは? ■ グローバルなのでアプリケーションのどこからでも呼び 出せる ■ Laravelに出てくる「app」はサービスコンテナのこと ■ resolveメソッドを使うことで サービスをコンテナから取得できる $controller = resolve(UserController::class);

Slide 42

Slide 42 text

サービスプロバイダとは? ■ サービスコンテナへのデータ登録を管理 – =サービスの生成方法を管理 ■ アプリケーションの初期化時にロードされ、 サービスコンテナの使用準備を行う ■ registerメソッドを使用してデータを登録できる

Slide 43

Slide 43 text

サービスプロバイダとは? ■ デフォルトでは、AppServiceProviderというものがある ■ AppServiceProviderに追加していくよりも、 サービスごとにプロバイダを作成していくと良い

Slide 44

Slide 44 text

サービスプロバイダのコード class SendGridServiceProvider extends ServiceProvider { public function register() { $this->app->bind('sendgrid', function ($app) { $sendGrid = new SendGrid(config('services.sendgrid.user.key')); return new SendGridService($sendGrid); }); } }

Slide 45

Slide 45 text

サービスプロバイダのコード class SendGridServiceProvider extends ServiceProvider { public function register() { $this->app->bind('sendgrid', function ($app) { $sendGrid = new SendGrid(config('services.sendgrid.user.key')); return new SendGridService($sendGrid); }); } } key

Slide 46

Slide 46 text

サービスプロバイダのコード class SendGridServiceProvider extends ServiceProvider { public function register() { $this->app->bind('sendgrid', function ($app) { $sendGrid = new SendGrid(config('services.sendgrid.user.key')); return new SendGridService($sendGrid); }); } } key value

Slide 47

Slide 47 text

コントローラのコード // sendgridのcontactに登録 $sendGridService = resolve('sendgrid'); $sendGridService->saveUser($user);

Slide 48

Slide 48 text

コントローラのコード // sendgridのcontactに登録 $sendGridService = resolve('sendgrid'); $sendGridService->saveUser($user); key

Slide 49

Slide 49 text

サービスコンテナのまとめ ■ DIを使うと、コントローラでnewがいっぱい出てくる ■ サービスコンテナはサービスをまとめて管理するツール ■ サービスコンテナはサービスの入ったグローバルな配列 ■ サービスの生成方法についてはサービスプロバイダに 記述する

Slide 50

Slide 50 text

まとめ

Slide 51

Slide 51 text

なぜサービスコンテナは難しいのか サービス DI サービス コンテナ インター フェース 自動注入

Slide 52

Slide 52 text

DIのまとめ ■ DIとは、インスタンスの生成に必要な設定を引数で渡し てあげること ■ 設定を外から渡すことで、インスタンスの設定を状況に 合わせて指定できる

Slide 53

Slide 53 text

サービスコンテナのまとめ ■ DIを使うと、コントローラでnewがいっぱい出てくる ■ サービスをまとめて管理するツール ■ サービスコンテナはサービスの入ったグローバルな配列 ■ サービスの生成方法についてはサービスプロバイダに 記述する

Slide 54

Slide 54 text

ご清聴 ありがとうございました

Slide 55

Slide 55 text

サービス DI サービス コンテナ インター フェース 自動注入 自動注入

Slide 56

Slide 56 text

Tips: 自動注入 ■ サービスコンテナに登録するときのキーをサービスのク ラス名にすると、ちょっとラクに書けます! ■ コントローラなどで、サービスを引数に入れると、勝手 にサービスコンテナからサービスを取得してくれます。

Slide 57

Slide 57 text

サービスプロバイダのコード $this->app->bind(SendGridService::class, function () { $sendGrid = new SendGrid(config('services.sendgrid.user.key')); return new SendGridService($sendGrid); });

Slide 58

Slide 58 text

サービスプロバイダのコード $this->app->bind(SendGridService::class, function () { $sendGrid = new SendGrid(config('services.sendgrid.user.key')); return new SendGridService($sendGrid); }); keyをクラス名に

Slide 59

Slide 59 text

コントローラのコード public function store(Request $request, SendGridService $sendGridService) { // …ユーザーのDB保存処理 // sendgridのcontactに登録 $sendGridService->saveUser($user); // …メール送信 // …ビューの表示処理 }

Slide 60

Slide 60 text

コントローラのコード public function store(Request $request, SendGridService $sendGridService) { // …ユーザーのDB保存処理 // sendgridのcontactに登録 $sendGridService->saveUser($user); // …メール送信 // …ビューの表示処理 } 型に先ほどのkeyを指定する

Slide 61

Slide 61 text

Tips: 自動注入 ■ サービスコンテナに登録するときのキーをサービスのク ラス名にすると、ちょっとラクに書けます! ■ コントローラなどで、サービスを引数に入れると、勝手 にサービスコンテナからサービスを取得してくれます。