LaravelでJSON Web Tokenを使った認証方法
Laravel
+ React
でサービスを構築した場合に、API
による認証方法としてJSON Web Token(JWT)
を使った例を紹介しようと思う。
JSON Web Tokenとは?
ネットわかりやすく書いてあったので引用させていただくと
JWT(ジョット)とは JSON Web Token の略で、電子署名付きの URL-safe(URLとして利用出来る文字だけ構成される)な JSONのことです。 電子署名により、JSON の改ざんをチェックできるようになっています。 ざっくり言うと、改ざんできない JSON ということになります。 引用:https://qiita.com/gctoyo/items/8d0ffb265845ab8cc87c#jwt-%E3%81%A8%E3%81%AF
というセキュアで便利なものである。
認証として利用する
認証として利用するためには、とても便利なライブラリがあるのでそちらを使う。
インストールに関しては、公式の方を参考にする。
Laravel Installation - jwt-auth
モデルの設定
設定自体もとても楽で、Laravel
にすでにある認証方法の一部変更するだけでいい。
実際の設定しているconfig/auth.php
はこのようになる。
<?php return [ 'defaults' => [ 'guard' => 'api', ], 'guards' => [ 'api' => [ 'driver' => 'jwt', # ここをjwtにする 'provider' => 'client', ], ], 'providers' => [ 'client' => [ 'driver' => 'eloquent', 'model' => App\Models\ClientAccount::class, ], ], ];
ログイン
ログイン時にはいくつかバリデーションを行い、レスポンスにはトークンを返している。
<?php public function login(Request $request){ config(['jwt.user' => Client::class]); $account = $this->clientAccount->getLoginUserByEmail($request->email); // Emailまたはstatusがマッチしない場合 if(!$account){ throw new AuthenticationException; } // passwordがマッチしない場合 if (!Hash::check($request->password, $account->password)) { throw new AuthenticationException; } // ログイン情報を保存するにチェックを入れた場合 if($request->remember){ if (! $token = Auth::guard('api')->setTTL(config('jwt.ttl_r'))->login($account)) { throw new AuthenticationException; } }else{ if (! $token = Auth::guard('api')->login($account)) { throw new AuthenticationException; } } return compact('token'); }
ユーザー側からの利用
トークンの利用については、API
利用時にAuthorization
ヘッダーにBearer: {取得したtoken}
を付与すればできる。以下の記事が参考になる。
感想
- JWTを使った認証もライブラリのおかげで楽に実装
- ただ、JWTに関しては色々言われてるので利用する場合はちゃんと勉強しとかないとなとおもった
Mackerel サーバ監視[実践]入門を読んで、監視の第一歩目を始めた話
はじめに
うちのサービスは1月の後半に正式リリースをして約2ヶ月。
スピード重視という言い訳をしつつ、監視をあまりやってこなかったのでここらへんでMackerelを使って監視していきたいと思う。
↓ 監視ちゃんと取り込むきっかけになった自分のブログ
Mackerelはサーバーの監視をするためのSaaSである。
特に何が良いって、はてなのインフラのノウハウがベースなのと、日本語ってのがいい。
似ているサービスとしては海外のDatadog
同じく海外のNew Relicがある。
そもそも監視の勉強が先?
自分は監視に関してはやんわりしか理解してないため、まずは入門本を読もうと思っていた。ただ、まずは監視の設定を先にやらないと今このとき何か起こったとき間に合わないため今回はMackerel
の方を先に読んだ感じだ。
こちらは読む予定の本。
ソフトウェアエンジニアのための ITインフラ監視[実践]入門
目次
- 1章 Mackerelとは何か
- 2章 Mackerelをはじめる
- 3章 監視する
- 4章 アラートを通知する
- 5章 プラグインを作る
- 6章 各種ツール連携と運用の効率化
- 7章 クラウド環境におけるMackerel
- 8章 発展的な機能
- 9章 付録
学んだこと
Mackerel
の設定本として買ったつもりが、監視をする意義や監視すべき設定など細かく書いてあってすごくためになった!監視の初学 + Mackerelの設定が同時にできるいうお得な気分だ。
第2章: Mackerelをはじめる
はじめてみた
導入して最初に目がついたのが、CPU200%。。。。(笑えないやつ)
でも、バッチ自体が止まったことないしなーとおもって細かくみてみると
steal
に200%もとられている。
t2インスタンス特有?のCPUクレジットの枯渇が問題っぽいのかー。
確かに最近バッチサーバーはずっと動いてたから、こちらは他のインスタンスに変更しよう。
キャパシティプランニングへの応用
こういう言葉があること自体初めて知った。
システムに求められるキャパシティ要件として、ビジネスレベル(データ処理需要、同時利用ユーザー数、同時セッション数など)、サービスレベル(トランザクション量、ネットワークトラフィック量、応答時間など)、リソースレベル(CPU利用率、ディスク利用率、ネットワーク利用率など)を検討し見積もりをする。この際、現状の最大負荷だけでなく、将来予測される最大負荷時にもサービスの水準を維持できるような設計を検討する必要がある。
引用: https://it-words.jp/w/E382ADE383A3E38391E382B7E38386E382A3E38397E383A9E383B3E3838BE383B3E382B0.html
まずはリソースを可視化したら、自分たちのCPUなどがどれくらい使われているのか?ピーク時には足りているのか?余らせてないか?などみてみる。
ちなみに自分たちのAPIサーバーは
やばい。使わなすぎている。無理して良いの使いすぎた・・・下げよう。
サービスメトリックス
PVなどもサービスの状態を可視化して経営層とみよう!ってことが書かれていたけど、今時別のツール使ってみてないかな?というツッコミ。
第3章: サーバ監視
何を監視
- 外形監視
- 死活監視
- リソース監視
- その他監視
ミドルウェアの監視
mysqlなどの場合別途プラグインをいれる。
行ロックなどの数も取れたりするみたい。
RDSの場合はこちらから。(後の章で説明ある)
監視ルールの考え方
「実際に対応するものだけに限定すべき」
設定する前は適当にCloudWatch
で色々設定してしまってたの反省。
オススメの監視設定フロー
① 全てのサーバに対してのCPU使用率、メモリ使用率、スワップ使用率、ファイルシステムの使用率の監視ルールを設定する ② 各種エラー系のメトリックの監視ルールを設定しておく ③ いったん様子見を見て、特定のロールだけ頻繁にアラートが来るようなら除外条件で無視するか、別途当該ロール用の監視ルールを作成する ④ 障害が発生したときに、特徴的な値の変化をしたメトリックについて監視ルールを作成する。同じ障害を早めに検知できるように、回帰的に監視ルールを育てる。
監視ルールを育てるって良い。 ②までやったけど、③と④はサービスごとによしなに設定だからこれからうちのも育ててこう。
Webシステムにおけるロール編成
構成については以下を参照とのこと。
Linux
でより多くのパラメーターを取得するには、mackerel-plugin-linux
でとれる。
Mackerel
のプラグインは豊富で誰でも作れるのでよさそう。
システムメトリックスの見方
コラムなのに6ページくらい使って監視項目の見方とか書いてくれてる。 少しだけ抜擢すると
ロードアベレージ 「ロードアベレージがある値以上になったら即座に問題である」はあまり意味がない。 それ以上に、どんどん右肩上がりのグラフになっているかの方が問題。マルチコアの考慮もして「loadavg/コア数」を指標とする方が良いみたい。 mackerel-pluglin-multicoreとかでうまく対応できる。
ここら辺のコラムが一番参考になったかもしれない・・・。
CPUのほうはメモ
cpu.user: カーネル以外が使用した時間の割合 cpu.iowait: I/O街により、アイドル状態であった時間の割合 cup.system: カーネルが使用した時間の割合 cpu.idle: I/O街がなく、かつCPUがアイドル状態であった時間の割合
6章: 各種ツール連携と運用の効率化
tmux-cssh x MackerelAPIで同時に多数のサーバーに入る技。
以前それを改造してawsのログイン機能作ったのでついでに(便利だよ)。
7章: クラウド環境におけるMackerel
AWSインテグレーションを使って、勝手に連携できる。
RDS
とかも含めて複数台でパラメーターとってる場合はどうするんだろうっておもってたけど、同じホストとしてパラメーター取得でもできるようで便利。
8章: 発展的な機能
CLI
を通じて、グラフなどもすべてJSON
で記述が可能とのこと。
Infrastructure as Code
ができるし、Ansible
などと合わせてインフラ周りを全てコードで管理できそう。
以前の会社でもdatadogのグラフ情報をコードにしてる方もいたなぁ。
まとめ
Mackerel
を設定するために読み始めた本だが、監視のいろはなども書いてあって凄く勉強になった。とりあえず監視を始めてみよう!って方にはオススメ。
まだまだデータ取り始めたばかりなのでこれからどんどん育てていった結果もかきたい。
PHPerKaigi 2018に行ってきたけどすごく良いイベントだった!
どうも、くずき(@kzkohashi)です。
2018年 3月9日(金)〜3月10日(土)に開催されたPHPer
たちのイベントにいってまいりました。
土曜日のほうしか参加できなかったけど、すごくよかった。
参加したセッションの内容だけメモります。
今からでも出来る!Webサービスモニタリング!!
発表時間ぎりぎりに登場する、そーだい(id:Soudai)氏の発表。
モニタリング全般の内容。
感想
- やろうやろうと思って機能作りを優先していた自分にはとても耳が痛い
- モニタリングしてないからインフラのリファクタもできないんだよ、ってのはすごく響いた
- カカカカックの人もよく言ってた気がするからそこら辺も参考にしよう
- 関係ないけどそーだいさんのブログ読み漁るとすごく参考になる
質問してみた
発表終了後に、質問させていただいた内容
Q1. サービスやインフラで何をモニタリングしていいのかがわからない場合はどうすればいいですか?今はDatadog検討してます。
答えてもらったんだけど、自分が勘違いしてるから割愛! (ちゃんとmackerel使いこなしたら理解できるはずなので、その時追記)
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
MySQL大好き@yoku0825氏の発表。
MySQLのデータをどうやって復旧させるのか、保存するのかっていう話。
感想
- 難しいところがところどころあるけど、データベース詳しくない自分でもとりあえずこういうふうに保存しておけばいいよっていうのが理解できてよかった
- RDSで自動バックアップで楽々してる人は知識として診たほうがいいと感じた
- データベースが得意そーだいさんが質問してたけど、むずすぎてよくわからない
質問してみた
帰り際に質問させていただいた内容
Q1. 現在RDSを使っていて、フルバックアップを使ってます。自分たちのサービスではとれくらいまでのデータを保存すればいのかとかあまりわかってないんですが・・どうしたらいいでしょうか?
(懇親会後で若干出来上がった状態で聞いたので、間違ってるかもしれません)
A1. binarylogを使って途中の状態を復帰した事例は、自社のサービスをいくつも運用していて、5年間で1度だけ。なので、サービスによるけど、基本的にはフルバックアップをしっかりとってれば最悪は免れる。(ここでそーだいさんもはいってきてどっちが言ったか忘れました)会社にリソースないなら、RDSならフルバックアップが30日間くらい保持できるから、それ+24時間分のbinary logをしっかりとっておけば問題ない。復帰もインスタンスたてるときにぽちぽちと設定するだけでできるから簡単。
こんなしょぼい質問にデータベースのスペシャリストの2人のお話聞けてよかった。
とりあえずちゃんと実践して、ブログで恩返ししよう・・(違。
追記 コメントで指摘していただいて、RDSはbinarylogでの復旧相当のやってくれていて、フルバックアップだけじゃなかった。 (そのぶん高いけど)
phpstorm/チーム開発/開発環境相談会に参加
Interactive Round Table
とよばれる、円卓でプロフェッショナルな方たちにと一緒に対話や相談ができるという素敵な場所で、@tadsan氏や@do_aki氏たちを中心とした円卓があったので相談させてもらった。(他にもいたのですが、全員把握しきれず・・)
面白くて、ほとんどの時間ここにいたので他のセッション聞くこと忘れてました。
内容を覚えてる限り書いてみる。
議論的な感じだったので、なんとなくよかった答えだけを書く
現在IntellijでPHPを書いてるんですけど、PHPStormのいいところどこですか?
Inttelij
と比べて、PHP
に特化してるぶん初期設定が楽。
あと、Inttelij
のプラグインと比べて新しい機能とか早く出たと思うからいいよ。
レビューどうしてます?(ザックリすぎた)
A1. インデントとかそういった機械的な物に関しては、sideci
やpsr-2
などで対応する。理由としては、人同士のレビューなどでどうしても細かすぎるとイラッとしてしまうため、そういうところはなるべく機械的にすること。
A2. 開発が5人とかに対してレビュワーが1人のため、コミットの分け方やコードスタイル(※多分社内の)に準じてない場合はすぐ直してもらっている。コードスタイルを公開したりするだけじゃすぐにはよくならないから、何回も指摘して、地道にいいコードをあげてもらえるよう努力している。
セキュリティどうしてますか?
A1. 外部のツールなど使って継続的にみている
(VAddy, AppScan, HACKER SAFEあたりの話がでていた)
リモートってどう思いますか?
A1. 拠点が違うだけでも会議とか難しいので、しっかり社内体制整えないとリモートは難しい。
A2. フルリモートじゃなくて、週1とかでやるタスクが決まっているならできるとおもう。社内業務委託的な感じで。
(感想) 今うちでもやってみてるけど、週1、2でやる場合ならやるタスクが決まってれば問題ない。ミィーティングなどに関しても今のところあんまり問題ないけど、これが複数人とかだと難しくなるんだろうなぁ。
misocaさんの参考になる。
Misocaのリモートワークのやり方2018 | toyoshiの日記
おまけ
まとめてくれて感謝
phperkaigiの感想
運営の方々のおかげで円滑に進むし、
普通は話せないプロフェッショナルな方達と色々な話ができてとてもよかっし、
飯もビールも厳選されててうまいし、
知り合い増えたし、
すごく刺激にもなって良いことづくしの会議でした。(褒)
あとアンカンファレンス(参加者主導型のブース)も非常に面白くて、これはもっかいやってほしいなと思った。
関西か福岡のはどっちか行きたいなーと思えるいい会議でした。
Laravel Meetup Tokyo Vol.10で「Laravelを始めてからDDDを実践するまで」について発表してきた
どうも、くずき(@kzkohashi)です。
先日「Laravel Meetup Tokyo Vol.10」で発表してきたのでその内容と他の方の発表について書いていこうと思う。
laravel-meetup-tokyo.connpass.com
発表資料
Laravel
を始めてからDDD
を実践するまでの過程について書いた内容。
なぜこの内容にしたかというと、そもそも自分はコードの書き方とか設計思想をぼんやりしか持っていなく、以下のようなことで悩んでいた。
- 設計する際に毎回設計内容がブレてしまう
- フレームワークに依存する設計にしてしまっている(FWの恩恵を受けないのは論外だけども)
- 設計について他の人と深い議論ができてない
ようは自分がいいなって思う設計を考えられてないってので悩んでいて、設計(今回だとDDD)について「理論」だけではなく、「実践」することで学習のイテレーションを回したいなって考えていた。
補足
Email
のValue Object
に外部も関係しそうな振る舞いを使っている例はそもそも設計的にいいのか怪しい- クリーンアーキテクチャ気味に書いてたつもりだけど、色々混同してるっぽいのでそこらへんは参考にしないほうがいい
と、恥ずかしながら怪しいところばかりで・・。
逆に質問した内容
「実際、DDDを実践してどうでした?」とLaravel Meetup
の主催者であるytake氏に聞いてみた。
ザックリ書くと(若干忘れたので間違ってたら補足くだせい)、
- 要件に対して実装みれば大体わかる
- パフォーマンス問題についてはクリーンアーキテクチャを実践していて、そもそもEloquentを使っていないのもあるけど困ったことがない
DDD
を本格的に実践している方が言っていたので、もっと深くやりたいなと思いました。
反省点
- DDD全くわからない人向けには不親切な資料になってしまった
- わかる人にも中途半端なないようになってしまった
- つまり、タイトルをとりあえず実践してみようぜ!!!的な実践することに特化した感じにすればよかった
- 直前にスライド増やしたのもあって、練習通りの時間じゃなかった(19分で終わるはずが4分オーバー・・すいません)
Laravel環境で取り入れているテストTips4選
SCOUTERでCTOやってられる、@kotamats氏の発表。
E2E
のテストする際に便利なAPIspec
や、 Golang
界で人気なTable Driven Test
などの内容。
資料もみやすいし、Table Driven Test
はなかなか熱そうなテストで面白そう。
[ GitPitch ] kotamat/pitch-20180308-laravel-meetup/master
そのあと、今回使用した資料作成ツールについてのブログも書いてた。
ソースコード書くときは使いたい!!
Eloquentの使い方を考え直してみた(LT枠)
いわずとしれた、zuckey_17氏の発表。
すごくわかる。最初の方とか自分もwith
とか便利なのあるの知らず、まじつらだった。
LumenでのAPI E2Eテストの実装例 (LT枠)
若干競合会社(書いてて気づいたw)で働いていられる、@shaka0maru氏の発表。
apidoc
はよさそう!最近swagger
で疲弊してきたし。
Laravelから学びレガシーと闘いはじめた(LT枠)
同じ苗字の大橋さんである,@blue_goheimochi氏の発表。
途中に差し込まれるphperkaigi
ネタが面白すぎて、それしか覚えてないけど・・、どうやってレガシーなコードをチームごとに落とせるかっていうことがよかった。後から気づいたことだけど、phperkaigi2018
のスタッフだから差し込んでたのか・・。
全体的な感想
- 会場提供者である
istyle
さんが技術的におもしろいことばかりしてる会社だった - クラフトビールよかった(提供: 転職ドラフト)
- 初めて
Laravel
のコミュニティに参加してみたけど、みんないいひとでよかった - 20分は長いようで短い
Laravelでバリューオブジェクトのみを実装する
どうも、くずき(@kzkohashi)です。
今回はDDD
における、バリューオブジェクトをLaravel
でどう表現するかについて書きたいと思います。
なぜバリューオブジェクト?
DDD
を学んでいる中で、実際にどうやったら実装に落とし込めるだろうか?って考えたときに、一番最小構成であるバリューオブジェクトから手をつけたほうがいいんじゃないかという話になった。
(もちろんユビキタス言語などを見つけてからの前提)
実装
Eloquent
から返却される値をすべてバリューオブジェクトにしてたら、時間も手間もかかってしまうので、一部ずつ変えていく。
今回はUser
の1カラムであるEmail
を例に変更してみる。
バリューオブジェクトの生成
<?php class Email implements \JsonSerializable { /** * @var string */ protected $value; /** * @param string $value */ protected function __construct(string $value) { if (is_null($value)) { throw new \InvalidArgumentException("Argument must be set. Passed value is empty"); } // 正しいメールアドレスかのチェック if (preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $value)) { throw new \App\Exceptions\EmailException(); } $this->value = $value; } /** * @return string */ public function value(): string { return $this->value; } /** * @param $string * @return bool */ public function equals(self $string) { return $this->value === $string->value; } /** * @param string $value * @return static */ public static function of(string $value) { return new static($value); } /** * @return string */ public function __toString() { return (string)$this->value; } /** * @return mixed|string */ public function jsonSerialize() { return $this->value; } }
construct
では、バリューオブジェクトを作成する際のルールなどを書いておく。
JsonSerializable
を継承しておく理由としては、response()->json
などを使用する際に、バリューオブジェクト->値
などになるため入れておいたほうが良さそう。
モデル
<?php class User extends Models { public function toValueObject() { // イミュータブルにするため $replication = $this->replicate(); // すでに作成してあるバリューオブジェクトを入れる $replication->email = new Email($this->email); return $replication; } }
実際の利用方法
<?php // カラムをバリューオブジェクトに変換 $user = User::find(1)->toValueObject(); // バリューオブジェクトの振る舞いを利用 $user->email->xxxx();
こんな形で利用している。
ただ、ロジックが大きくなってしまう仕様や、判定ロジックは外部に切り出したりしている。
ここガッツリ書けなかったので、この方の記事が参考になると思います。
また、バリューオブジェクト=不変性だと思っていたのですが、かとじゅんさんが昔に書いた記事が参考なります。
感想
DDD
が書いてある本などを読んでいると、設計方法はやんわりわかったけど実際動いてるコードはどこから手をつけたらいいかわらかなかった。
今回はバリューオブジェクトから始めることによって、ドメインロジックに集中するって大切さが少しわかってきた。
Laravelでリポジトリーパターンを実装して見た感想
どうも、いっき(@kzkohashi)です。
Laravel
を使い始めて1年くらいたちそうなので、いくつか試している実装パターンの感想でも書こうと思う。
今回は、Repository
パターンについて書く。
---追記---
リポジトリーパターンを採用しつつバリューオブジェクトについても書いた。
また、Laravel MeetupでDDDについても発表したまとめ。
Repositoryパターンとは?
Repository
パターンとはビジネスロジックとデータ操作のロジックを分離し、データ操作のロジックを抽象化するパターンと認識してる。
例えばユーザーが新規登録したとして、今までだと
View -> UserController -> UserSerive(ビジネスロジック/データ操作)
View
から受け取ったフォームデータをコントローラーで受け、サービス層で登録処理などをやっていたと思う。
それをRepository
パターンにおきかえると
View -> UserController -> UserSerive(ビジネスロジック) -> UserRepository(データ操作)
このようになり、データ操作のロジックとビジネスロジックを分離する。
Repository
パターンのほうの実装を簡単に書くと(Controllerは省略)
<?php interface UserRepository { public function create($name, $email, $password_hash); } class EloquentUserRepository implements UserRepository { private $user; public function __construct(User $user) { $this->user = $user } public fucntion create($name, $email, $password_hash) { $data = []; $data['name'] = $name; $data['email'] = $email; $data['password] = $password_hash; return $this->user->create(data); } }
<?php class UserService { private $user_repo; public function __construct(UserRepository $user_repo) { $this->user_repo = $user_repo; } public function regist($name, $email, $password) { $password_hash = bcrypt($password); $user = $user_repo->create($name, $email, $password_hash) $user->notify(); return $user; } }
注目すべきところはサービスからUserRepository
が呼ばれているが、実装はEloquentUserRepository
で行なっていること。
理由としてはインターフェースを通して実行することで、ORM
による依存を排除し、サービス側は実装の内容を意識しなくて良い。
Laravelでの実装
簡単にテストまでの奴を書いた。
簡単に構成を説明すると、
- インターフェース:
App\Repositories
- 実装:
App\Infrastracture\Repositories
- サービスコンテナの登録:
App\Providers\RepositoryProvider
らへんを見てもらえるとリポジトリーパターンの実装の仕方がわかると思う。
リポジトリの作成は結構手間だけど、aiiroが実装してくれたコマンドを使えば容易に作れる。
php artisan app:make:repository ItemRepository
良かったところ
悪かったところ(反省点?)
- Eloquentがサービス層に漏れている
- 結局返す値がEloquentじゃデータ操作ができてしまう
- 完璧なリポジトリーパターンを目指すには、Entityでのやりとりなどが必要
今後の改善点
リポジトリーパターンはDDD
を行うための実装方法の一つで、実際すべてを行うのはなかなかしんどい。
なので次はEloquent
の一部の値をValueObject
に置き換え、DDD
に近づけていく。
LaravelのMacroを使ってBuilderに機能を追加する方法
どうも、くずき(@kzkohashi)です。
先日、正しいJSON API
のフォーマットにするために以下のライブラリを導入した。
paginateは正しいクエリーパラメーターを取っていない
恥ずかしながら最近知ったのだが、Eloquent
で使用しているpaginate
は、完璧なJSON API
のフォーマットに対応していない。
ページ番号で使われるpage=2
などのクエリパラメーターは、正しくは、page[number]=2
にすべきみたいだ。加えて、ページ番号だけでなく、そのページにどれくらい表示させたいかなどはpage[size]=20
で表現する。
なので、導入前と導入後ではこうなる。
導入前
xxx.com/xxx?page=2&size=20
// sizeに関しては独自実装
導入後
xxx.com/xxx?page[number]=2&page[size]=20
さらにきになる方は以下を参照。
Note: JSON API is agnostic about the pagination strategy used by a server. Effective pagination strategies include (but are not limited to): page-based, offset-based, and cursor-based. The page query parameter can be used as a basis for any of these strategies. For example, a page-based strategy might use query parameters such as page[number] and page[size], an offset-based strategy might use page[offset] and page[limit], while a cursor-based strategy might use page[cursor].
JSON API — Latest Specification (v1.0)
ライブラリの実装を見て見る
ここからが本題。
このライブラリを導入し、設定ファイルを書くとjsonPaginate()
が使えるようになる。
YourModel::where('my_field', 'myValue')->jsonPaginate();
どうやって実装したんだろうとコードをみて見るとBuilder::macro
によって独自の関数を追加できるみたいだ。
<?php ... Builder::macro(config('json-api-paginate.method_name'), function (int $maxResults = null, int $defaultSize = null) { $maxResults = $maxResults ?? config('json-api-paginate.max_results'); $defaultSize = $defaultSize ?? config('json-api-paginate.default_size'); $numberParameter = config('json-api-paginate.number_parameter'); $sizeParameter = config('json-api-paginate.size_parameter'); $size = request()->input('page.'.$sizeParameter, $defaultSize); if ($size > $maxResults) { $size = $maxResults; } return $this->paginate($size, ['*'], 'page.'.$numberParameter) ->setPageName('page['.$numberParameter.']') ->appends(array_except(request()->input(), 'page.'.$numberParameter)); });
これはLaravel
のMacro
という機能で、Laravel
が提供している機能に独自のメソッドなどを拡張実装できるみたい。
Builder
以外には、HTML
, Response
などを拡張できる。
他にどう使えるか?
例えば、Eloquent
が返すModel
ではなく、独自に実装したEntity
を返すcollection
を用意するとか
<?php Builder::macro('toDomainCollection', function () { /** @noinspection PhpUndefinedMethodInspection */ return $this->get()->map(function (Domainable $model) { return $model->toDomain(); }); });
レスポンスである条件の時に決まった内容などを送る時とか
<?php Response::macro('notPermitted', function ($type = null) { if (strtolower($type) === 'success') { return $this->json(['data' => []], 200); } return $this->json(['data' => []], 403); });
今まで作ってたやり方を見直すだけでも色々ありそーだなーと思います。