3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravel API 多次元連想配列のリクエストパラメータをスネークケースに変換する関数【改良版】

Posted at

はじめに

Laravelを用いたAPI開発で、フロントエンドからのリクエストパラメータを「キャメルケース」と「スネークケース」両方とも許容できるようにするタスクのメモ。

以前、同タスクの内容を以下でまとめたのだが、今回はロジックを一新したのでまとめる。

上記事では階層の制限があるロジックだったが、今回は制限や条件なしで動く関数を作成できた。
また、本記事では関数の部分のみ記事にするので、関数以外の部分は上の記事を参考に。

目次

  1. 前提の仕様
  2. 関数
  3. 参考文献

前提の仕様

・フロントからのリクエストパラメータを「キャメルケース」と「スネークケース」両方許容できるように
・バックエンド側では「スネークケース」に統一する
・アプリ内のすべてのPOSTリクエストに対応(リクエストオブジェクトの構造やパラメータは各処理によって異なり、多次元配列もある)

関数

再起処理による関数

public function handle(Request $request, Closure $next)
{
    $array_snake_recursive = function($array, $new_array=[], $keys=[]) use(&$array_snake_recursive) {
        foreach ($array as $key => $value) {
            if (preg_match('/[A-Z]/', $key)) {
                $key = Str::snake($key);
            }

            $index = count($keys);
            if (is_array($value) && count($value) > 0) {
                $new_array[$index][$key] = [];
                $keys[] = $key;
                $new_array = $array_snake_recursive($value, $new_array, $keys);
                array_splice($keys, -1);
                array_splice($new_array, -1);
            } else {
                $new_array[$index][$key] = $value;
            }
        }

        // 一個上の階層に代入
        if ($index > 0) {
            $new_array[$index-1][$keys[$index-1]] = $new_array[$index];
        }

        // 再起処理の最後のみ
        if (count($new_array) === 1) {
            $new_array = $new_array[0];
        }

        return $new_array;
    };

    $array = $request->all();
    $new_array = $array_snake_recursive($array);
    $request->replace($new_array);
    
    return $next($request);
}

【ロジック】

Str::snake()でスネークケースへ変換
$index$keysの要素数

$new_array[]は2階層構造で、1階層目はインデックス番号、2階層目はオブジェクト(キー:バリュー)の形で入れていく
$keys[]は インデックス:値(キー名)の構造

・条件式によって処理を分ける
 foreach内$valueの値がarray型かつ要素数が1以上だった場合(if)
  再起処理の前
   ・$keys$keyを代入
   ・$new_array[$index][]を代入
  再起処理を走らせる
  再起処理の後
   ・$keysの末尾を削除
   ・$new_arrayの末尾を削除
 foreach内$valueの値がstring型 or NULL or array型かつ要素数が0の場合(else)
 ・$index$keysの値を使い、変数で$new_arrayのキー(名)を指定し、$valueの値を代入

例を交えて説明する

例)リクエストされた元配列
$original_array = {
    "A": "値",
    "B": {
      "C": {
         "D": "値" 
      },
      "E": "値"
    },
    "F": {
      "G": "値"
    }
}

以下、再起処理、$original_array["b"]["c"]["d"]を処理中の状態

$new_array = [
    0: { "a": "値" }, { "b": [] },
    1: { "c": [] },
    // 2: { "d": "値" } // 後述のelseのところでこうなる
]
$keys = [
    0: "b",
    1: "c",
]

処理してる箇所

else {
    $new_array[$index][$key] = $value;
    // 例) -> $new_array[2]["d"] = "値";
}

・下の階層の値を一個上の階層の配列に代入する(dをcに代入、cをaに代入していく)

if ($index > 0) {
    $new_array[$index-1][$keys[$index-1]] = $new_array[$index];
    // 例) -> $new_array[1]["c"] = $new_array[2];
}

処理終わり次第
$new_array[]のインデックス0以降の末尾を削除する
$keys[]の末尾を削除する
(dの処理が終わった後、cのforeach終了)

array_splice($keys, -1);
array_splice($new_array, -1);

以上を再起的に繰り返していく

ちなみに以下再起処理、$original_array["f"]["g"]を処理中の状態

$new_array = [
    0: { "a": "値" }, { "b": { "c": { "d": "値" }, "e": "値" } }, { "f": [] },
    // 1: { "g": "値"} // elseの処理でこうなる
]
$keys = [
    0: "f",
]

処理してる箇所

else {
    $new_array[$index][$key] = $value;
    // 例) -> $new_array[1]["g"] = "値";
}

if ($index > 0) {
    $new_array[$index-1][$keys[$index-1]] = $new_array[$index];
    // 例) -> $new_array[0]["f"] = $new_array[1];
}

再起処理の最後の$new_arrayの状態

$new_array = [
    0: { "a": "値" }, 
       { "b": {
           "c": { 
             "d": "値" 
           }, 
           "e": "値" 
         } 
       }, 
       { "f": {
             "g": "値"
          }
       }
]

最後に構造を整えてreturnする

// 再起処理の最後のみ
if (count($new_array) === 1) {
    $new_array = $new_array[0];
}

上記ロジックでは構造や階層の深さがどんな配列でも対応できる(はず)

終わりに

いいのができた気がする。
バグやもっといいアイデアあったらご教授ください。

参考文献

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?