LoginSignup
0
1

More than 3 years have passed since last update.

Laravelで更新項目をkey-valueで取得して動的にValidationを実施して更新を実施する

Last updated at Posted at 2020-09-09

TL; DR

APIの開発をしていると、通常はFormRequestで更新項目を取得し、validationを実施します。

しかし、更新する項目のみをリクエストとして送信する、かつ1項目のみとする場合は、通常の実装ではこの限りとはなりません。

そのため、少しとトリッキー冗長なやり方で実装してみます。

環境

  • PHP7.4
  • Laravel7.2

通常の更新処理の実装

通常、以下の要領で更新処理のリクエストを送信します。

{
  "name": "名前",
  "mail": "test@exmaple.com",
  "gender": 1 
}

このリクエストに対応するFormRequestは、以下のとおりです。

<?php


namespace App\Http\Request\Api;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class UpdateRequest extends FormRequest
{
    /**
     * @return bool
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            'name' => ['required', 'string'],
            'mail' => ['required', 'email'],
            'gender' => ['required', Rule::in(1,2)],
        ];
    }

    /**
     * バリデーションエラーのカスタム属性の取得
     *
     * @return array
     */
    public function attributes()
    {
        return [
            'name' => '名前',
            'mail' => 'メールアドレス',
            'gender' => '性別',
        ];
    }
}

key-value形式での実装

今回は、以下の形式で更新する項目名をkeyに、更新する値をvalueに含めたリクエストを送信します。

{
  "key": "mail",
  "value": "test@exmaple.com"
}

この場合、通常通りの実装では、Validationは十分にできません。それは、keyで渡される項目をどのルールを適用してValidationの検証をすればよいかわからないからです。

そのため、Validationをする項目を動的に設定するように対応します。

<?php


namespace App\Http\Request\Api;

use App\Enum\Gender;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class UpdateRequest extends FormRequest
{
    private array $keys = [
        'name', 'mail', 'gender'
    ];

    /**
     * @return bool
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * @return array
     */
    public function rules(): array
    {
        return [
            'key' => ['required', 'string', Rule::in($this->keys)],
            'value' => ['required'],
            'name' => ['max:15'],
            'mail' => ['email'],
            'gender' => [Rule::in(Gender::validateList())],
        ];
    }

    /**
     * Get data to be validated from the request.
     *
     * @return array
     */
    public function validationData()
    {
        $data = $this->all();
        if (empty($data['key']) || empty($data['value'])) return $data;

        // keyで設定された値を連想配列のキーとして設定する
        $data[$data['key']] = $data['value'];

        return $data;
    }

    /**
     * バリデーションエラーのカスタム属性の取得
     *
     * @return array
     */
    public function attributes()
    {
        return [
            'key' => '項目名',
            'value' => '属性値',
            'name' => '名前',
            'mail' => 'メールアドレス',
            'gender' => '性別',
        ];
    }
}

先ず、ruleメソッドでは、keyvalueを必須項目に設定します。また、このとき設定可能とするkeyの値を$keysで取得し、keyのValidationルールにRule::in($thit->keys)を設定します。

しかし、そのままだとValdiationの検証をしたい項目とそのルールが紐づいていません。そのため、Validationが実施される前に呼び出さるvalidationDataメソッドにて、あたかもその項目でリクエストが来たかのようにふるまうよう、値の置き換えをします。

     public function validationData()
    {
        $data = $this->all();
        if (empty($data['key']) || empty($data['value'])) return $data;

        // keyで設定された値を連想配列のキーとして設定する
        $data[$data['key']] = $data['value']; // ここで値の置き換え

        return $data;
    }

この処理をすることで、あたかも以下の形式のリクエストが送信されたかのようにふるまうことができます。

変換前のリクエスト

{
  "key": "mail",
  "value": "test@exmaple.com"
}

変換後のリクエスト

{
  "mail": "test@exmaple.com"
}

更新処理の際には、key-valueの各値を更新値の連想配列に含めれば更新が実施されます。

    /**
     * @param UpdateRequest $request
     * @return JsonResponse
     */
    public function __invoke(int $id, UpdateRequest $request): JsonResponse
    {
        $user = User::find(id)->get();

        $user->update([
            $request->get('key') => $request->get('value')
        ]);

        return response()->json($user, 200);
    }

果たして、使いどころがあるかはわかりませんが、動的にValidationを行う一例でした。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1