---
# System prepended metadata

title: OKR app 理解度テスト (模範回答)

---

# OKR app 理解度テスト (模範回答)

1. abstract クラスの実装・使い方について解説してください
1. Interface の実装・使い方について解説してください
1. HTTP Request メソッドの種類について解説してください
1. resouce メソッドで生成されるルーティングについて、それぞれの役割、HTTP Request メソッドの種類、アクションがとる (一般的な) 引数を解説してください
1. FormRequest の役割、実装について解説してください
1. DI について解説してください
1. コンストラクタインジェクションについて解説してください
1. メソッドインジェクションについて解説してください
1. Fat Controller はなぜよくないのか、Laravel でそれを回避するにはどのような実装が有効か解説してください
1. useCase の役割・実装・呼び出しについて解説してください
1. Service の役割・実装・呼び出しについて解説してください
1. Facade の役割・実装・呼び出しについて解説してください
1. Respository の役割・実装・呼び出しについて解説してください
1. Respository を Interface の型でコンストラクタインジェクションする理由、その設定を ServiceProvider と ServiceContainer を交えて解説してください
1. モデルの Relation (Asscoiation) の定義、使い方について解説してください
1. モデルの Accessor の定義、使い方について解説してください
1. モデルの find / get / where の戻り値について解説してください
1. Gate の実装・使い方について解説してください
1. Policy の実装・使い方について解説してください

## 回答

1. - abstract はインスタンス化できない。継承が前提
   - 継承先で使ってほしいメソッドを事前に実装しておく
   - 継承先で自由に中身を実装ほしいメソッドであれば abstract メソッドにする
   - 今後、似たようなクラスが増えていくことが見込まれる場合に汎用的な共通処理を定義しておくクラス
1. - このメソッドが必ず実装されてます、と約束させるファイル
   - たとえば API を一般公開するような場合、interface の型で実装しておくと利用者は安心だし、実装の中身は見ずに Interface だけ確認するだけで済む
   - 開発時には、実装漏れがないか、もしくは Interface 側に定義漏れがないか二重チェックになる
1. - GET: a タグなどによるリクエスト
   - POST: form タグなどによるリクエスト
   - PUT: 全体更新 / PATCH: 部分更新
   - DELETE: データ削除
   - など。。。実際は他にもたくさんあります
1. 

| method | URL | action |役割|
| -------- | -------- | -------- |---|
|GET     | /hoge     | index     |データ一覧|
|GET     | /hoge/create     | create     |新規作成画面|
|POST     | /hoge     | store     |新規作成処理|
|GET     | /hoge/{id}     | show     |データ詳細画面|
|GET     | /hoge/{id}/edit     | edit     |編集画面処理|
|PUT/PATCH     | /hoge/{id}     | update     |編集処理|
|DELETE     | /hoge/{id}     | destroy     |データ削除|

5. - リクエスト内容のバリデーション
   - コントローラや Service 内でバリデーション処理をしなくてすむようになるくなる
       - FatController を避けることができる
   - コントローラアクションに対するメソッドインジェクションで実装
1. - プログラムのメイン処理内で必要なときにインスタンス生成するのではなく、前もって必要なインスタンス生成を行っておくこと
   - 依存性注入ともいう
1. - Laravel のコンストラクタでは基本的にどんなクラスでも引数で受け取ることができる
   - 受け取った時点ですでにインスタンス生成されているので、メンバ変数に保存しておく
   - 設定は不要
1. - Controller のアクション引数では基本的にどんなクラスでも引数で受け取ることができる
   - 受け取った時点ですでにインスタンス生成されているので、メンバ変数に保存しておく
   - 設定は不要
1. - 長い行数のプログラムは可読性が低くなり、読み手も辛いし、書き手もバグを生みやすい
   - 長い行数のプログラムはたいてい複数のメソッドに切り分けることができるので、そこで適切なメソッド名・引数をつけていれば処理の役割を明確にすることができる
   - 実際、phpstan や phpinsight で長い行数 （30行以上くらい） があるとスコアが下がってしまう
   - テストの観点からも、長い行数のメソッドは単体テストしにくい
       - 特に Controller のアクション内に処理をたくさん書いてしまうと HTTP Request を投げるテストコードから書かないといけなくなるので負担がとても大きくなる
   - FormRequest / useCase / Sevice / Facade / Repository などが代表的なワークアラウンド
1. - メソッドインジェクションで呼び出し
   - 実行すると `__invoke()` がコールされる
   - 他にメソッドを定義することはできない
   - 処理が長くなるようなら Service クラスに書き出すことも検討できる
1. - メソッドインジェクション、もしくはコンストラクタインジェクションで呼び出し
   - 様々なアクセス修飾子でメソッド定義可能
1. - use するだけで仕様可能。メソッドインジェクション、コンストラクタインジェクションも不要
   - たとえば `Auth::use()` といった非常に汎用性の高い、どこでも使いそうな処理は Facade 登録しておくのがラク
   - ただし以下の設定が必要
       - ServiceProvider の作成
       - Facade クラスの作成
       - 上記 2 つを `config/app.php` に Facade として紐付ける
   - ide-helper を使わないとコードジャンプできないというデメリットがある
1. - Model を使った CRUD 系の処理は Repository で一元管理するといい、というアーキテクチャ
   - 戻り値は Collection 型にするのがベストプラクティス
       - つまり `find($id)` ではなく `where('id', $id)->get()` などを積極的に使う
       - `find（$id）` を使いたい場合も `findOrFail($id)` で代用すると null のとき Exception で検知できる
   - 当然のことながら、ただのクラスなのでコンストラクタインジェクションで呼び出し可能
1. - Repository を使いたい場合は該当する Interface 型でコンストラクタインジェクションするべきである
   - そうすることで Interface にあるメソッドの実装漏れ、もしくは Interface 側の定義漏れを検知できるようになる
   - Repository はあらゆるクラスからメソッドが呼ばれる可能性があるので Interface はしっかり定義しておいたほうがいい
   - ただし Interface 自体はインスタンス生成できないので、設定をしないとコンストラクタインジェクション実行時にエラーになってしまう
       - Repository 専用の ServiceProvider を用意し、「インターフェイスのクラス名」でインジェクションしようしたら「実装クラス名」でインスタンス化するという紐付けを行う
       - `config/app.php` に ServiceProvider の登録が必要
   - このような暗黙的にインスタンス化する機構を ServiceContainer という ※ DI と言ってもいい
   - 最近の Laravel はメソッドインジェクション / コンストラクタインジェクションの設定はいらないが、Facade の利用や Interface によるコンストラクタインジェクションを行いたい場合は DI の設定が必要
1. - 外部キーで JOIN するクエリ発行なしで、いきなりモデルのオブジェクトから外部キーオブジェクトを参照できる仕組み
1. - DB カラムとしては存在しなくても、モデルの attribute にはプログラムで独自の値を仕込んでおくことができる
   - たとえば User モデル内で `setHogeHogeAttribute` したら `$user->hoge_hoge` で呼び出せる
1. - find
       - ?Model が戻り値
       - つまり null の可能性がある
       - null なのに `$model->name` などで attribute アクセスしたらヌルポで落ちるので注意
   - get
       - Collection が戻り値
       - データ件数が 0 でもちゃんと Collection が返ってくるので安心
           - `$collection->first()` で 1 件目のデータだけを取れたりするので find と同じことができる。その際に null チェックなどしてあげればいい
           - クラス型は Array じゃないので配列ではないが、まるで配列のように扱うことができる
               - `foreach` で要素である Model を取り回すことができる
               - `count()` で要素である Model の件数を知ることができる
    - where
        - get() される前なので Collection ではなく Builder 型が戻り値になる
        - クエリの「実行結果」ではなく、「実行中」のオブジェクトなイメージ
1. - そもそもページ遷移させない、といった制御ができる
   - (例) マネージャ以上じゃないと View でボタンを表示しない
       - blade 内で `@can('manager-higher')`
   - ルーティングの制御も可能
       - `web.php` で `Route::middleware('can:manager-higher')`
1. - アクションメソッド内で「権限や条件を満たしていないからエラーにする」といった制御ができる
   - (例) マネージャ以上じゃないのに削除処理しようとしているからエラー画面に遷移させる
       - コントローラの destroy アクション内で `$this->authorize('delete', $user);`
       - Policy クラスに定義されている delete メソッドを呼び出して、`$user` を使った判定を行われる
       - Routing で resouce メソッドを使った場合は Policy に定義するメソッド名と Controller のアクションメソッド名と紐付いている
       - その場合はコントローラのコンストラクタに `$this->authorizeResource(Post::class);` と書くだけで全てのアクションに policy が紐づく

| Controller | Policy | 
| -------- | -------- | 
| index     | viewAny     | 
| show     | view     | 
| create     | create     | 
| store     | create     | 
| edit     | update     | 
| update     | update     | 
| destroy     | delete     | 
