転職活動管理アプリを作ろう⑦（各メニューの作成＝完成）

前回の記事は [コチラ](https://qiita.com/soso555/items/1d355c30c176c2bc396a)

# 概要
- [テーブル定義した内容](https://qiita.com/soso555/items/89acdd45e88d0e0251f1) をもとに各メニューを作るだけだが、それぞれ特殊なことをやったので手順を記す

# 各テーブルごとの作成手順
## エージェント
- [以前実施した内容](https://qiita.com/soso555/items/5f69b0e159e1087a17ab#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E4%BD%9C%E6%88%90) を参照

## エージェント担当者
- マイグレーションファイル、モデル、コントローラの作成はエージェントと同じ
- マイグレーションファイル
    - 外部キー（エージェント：エージェント担当者＝１：多）の設定

        ```php
        Schema::create('agent_recruiters', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('agent_id');
            $table->string('name');
            $table->string('email');
            $table->boolean('active')->default(true);

            $table->timestamps();

            $table->foreign('agent_id')->references('id')->on('agents')->restrictOnDelete()->restrictOnUpdate();
        });
        ```

- モデル
    - 外部キー（エージェント：エージェント担当者＝１：多）の設定
        - Agent::class

            ```php
            namespace App\Models;
            
            use Illuminate\Database\Eloquent\Factories\HasFactory;
            use Illuminate\Database\Eloquent\Model;
            
            class Agent extends Model
            {
                use HasFactory;
            
                public function agent_recruiter()
                {
                    return $this->hasMany(AgentRecruiter::class);
                }
            }
            ```

        - AgentRecruiter::class

            ```php
            namespace App\Models;
            
            use Illuminate\Database\Eloquent\Factories\HasFactory;
            use Illuminate\Database\Eloquent\Model;
            
            class AgentRecruiter extends Model
            {
                use HasFactory;
            
                public function agent()
                {
                    return $this->belongsTo(Agent::class);
                }
            }
            ```

- コントローラ
    - AgentController
        - ひもづく AgentRecruiter の数を一覧に表示し、AgentRecruiter の検索結果画面へのリンクを追加する
            - grid() メソッドに以下を追加

                ```php
                $grid->column('agent_recruiter', 'Recruiters count')->display(function ($recruiters) {
                    $count = count($recruiters);
                    return "<span class='label label-warning'>{$count}</span>";
                })->link(function ($row) {
                    return route('.agent_recruiters.index', ['agent_id' => $row->id]);
                });
                ```

            - 結果

                ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/faa4bb6f-6e6d-1941-8afe-a7748abcd87d.png)

        - 詳細画面にひもづく AgentRecruiter の一覧を表示する
            - detail() メソッドに以下を追加

                ```php
                $show->agent_recruiter('Recruiters', function($recruiters) {
                    $recruiters->resource('/agent_recruiters');
        
                    $recruiters->id();
                    $recruiters->name();
                    $recruiters->email();
                });
                ```

            - 結果

                ![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/b5245d41-9348-8552-3a1f-b52f02e4e117.png)

    - AgentRecruiterController
        - ひもづく Agent の名前を一覧に表示する
            - grid() メソッドに以下を追加

                ```php
                $grid->column('agent.name');
                ```

        - 詳細画面にひもづく Agent の一覧を表示する
            - detail() メソッドに以下を追加

                ```php
                $show->agent('Agent information', function ($agent) {
                
                    $agent->setResource('/agents');
                
                    $agent->id();
                    $agent->name();
                });
                ```

            - 結果

                ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/c55b91f9-5c12-0ab7-adf4-4d5f52aa9fb8.png)

        - 新規作成・更新画面に Agent の選択肢を表示する
            - form() メソッドに以下を追加

                ```php
                $form->select('agent_id', __('Agent id'))->options(Agent::all()->pluck('name','id'));
                ```

            - 結果

                ![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/52b6beb1-bb35-4231-b5ff-ff7db9a2d01c.png)

        - 一覧画面に Agent 詳細画面へのリンクを追加する
            - grid() メソッドに以下を追加

                ```php
                $grid->column('agent.name', __('Agent'))->link(function ($row) {
                    return route('.agents.show', ['agent' => $row->agent]);
                });
                ```

            - 結果

                ![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/c05304ee-701c-65e0-e1d2-6d942c5de531.png)

## 企業
- エージェントと同じ

## 企業の求人票
- エージェント担当者と同じ

## 企業の評価ポイント
- エージェント担当者と同じ

## 企業のマークダウン形式メモ
- コントローラ
    - CompanyMarkdownController
        - 新規作成/編集時にマークダウンエディタを使用する
            - laravel-admin の拡張 SimpleMDE を [インストールしておく](https://qiita.com/soso555/items/5f69b0e159e1087a17ab) こと
            - form() メソッドに以下を追加

                ```php
                $form->simplemde('content', __('Content'));
                ```

            - 結果

                ![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/cc7289c3-e185-f5e7-d49d-c91c324a0fa1.png)

        - 閲覧時にマークダウンを HTML に変換して表示する
            - composer で joyqi/hyper-down をインストールしておくこと
                - ```$ composer require joyqi/hyper-down```
            - app/Admin/Extensions に以下クラスを作成
                - 詳細画面でのフィールド拡張を実装する（詳細は [このドキュメント](https://laravel-admin.org/docs/en/model-show-extension) を参照）

                ```php
                namespace App\Admin\Extensions\Show;
                
                use Encore\Admin\Show\AbstractField;
                use HyperDown\Parser;
                
                class MarkdownParser extends AbstractField
                {
                    public function render($arg = '')
                    {
                        $parser = new Parser();
                        return $parser->makeHtml($this->value);
                    }
                }
                ```
            - app/Admin/bootstrap.php に以下を追加
                - 作成した拡張機能を登録する

                ```php
                Encore\Admin\Show::extend('markdownparser', App\Admin\Extensions\Show\MarkdownParser::class);
                ```

            - detail() メソッドに以下を追加

                ```php
                $show->(DBのカラム名)()->unescape()->markdownparser('xxx');
                ```

                - unescape() を付けないと、html タグが文字列としてそのまま出力される
                - __(DBのカラム名)__ は、例えばカラム「content」だった場合は content() となる


            - 結果

                ![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/a2874e17-55d7-4ee5-9093-ab3c676e9024.png)


# 所感
- マークダウンの HTML 変換部分が少し苦労した
    - パーサーの導入と、laravel-admin のフィールド拡張実装が手間でした
        - 参考：https://www.dazhuanlan.com/miyowhale/topics/1550172
- 動作確認をするとちょこちょこエラーが起きたが、ほとんどは自分のtypo
    - 人を疑う前にまず自分を疑うのが大事
- このまま AWS で VPC を構築してドメイン取って...と進もうと思ったが、同じアプリを Ruby on Rails で作りたくなった
    - ので、Rails で作った後にそれを乗せる VPC を作ろうと思う