はじめに
今回、個人開発で提案商品という複数選択可能な配列形式のフィールドをforeach文で回しつつ、下記のような
処理を実装する機会があったので今後の自分用の忘備録として記事をまとめていきます。
・送られてきた提案商品IDとDBに格納している提案商品IDに差分があった場合、DBに格納されている提案商品のレコードを削除。
・そもそもリクエストとして送られてきた値に、提案商品IDが含まれておらず、その代わりに他の値が入っていた場合は
提案商品テーブルにレコードを新規作成。
・送られてきた提案商品IDと、DBに格納されている提案商品IDに差分がない場合、一致する場合はその提案商品IDのレコードの修正内容を更新する。
前提条件
仕様としては、提案商品編集というボタンがあり、そのボタンを押すと各商品、提案内容を入力出来て
商品名と、提案内容のセットが複数登録出来るという内容です。
提案商品テーブルに、商品IDが56、57のレコードが元々登録されていて、どちらかの商品を削除したい場合は
商品名の横に ×ボタンが付いており それを押すとフロント側でその商品の表示が削除される仕組みとなっており
その時点ではDBのレコードに対しては何も影響が起きず、バックエンド側に送られるリクエストの値が下記のように
変化するという仕組みです。
削除前
"proposed_product": [
{
"proposed_product_id": 9,
"negotiation_id": 10,
"general_product_id": 1,
"broadcast_product_id": "",
"other_product_id": 1,
"list_price": 100,
"selling_price": 2000,
},
{
"proposed_product_id": 10,
"negotiation_id": 10,
"general_product_id": 1,
"broadcast_product_id": "",
"other_product_id": 1,
"list_price": 1000,
"selling_price": 2000,
},
削除後
"proposed_product": [
{
"proposed_product_id": 9,
"negotiation_id": 10,
"general_product_id": 1,
"broadcast_product_id": "",
"other_product_id": 1,
"list_price": 100,
"selling_price": 2000,
},
また編集ボタンを押して、そこから新しく提案商品を登録したい場合は下記のように入力フィールドにproposed_product_idという提案商品IDは格納されないという仕組みにします。
"proposed_product": [
{
"negotiation_id": 10,
"general_product_id": 1,
"broadcast_product_id": "",
"other_product_id": 1,
"list_price": 100,
"selling_price": 2000,
},
API側(Laravelのコントローラー側)の処理。
public function example(Request $request)
{
$params = $request->all();
DB::beginTransaction();
try {
$active = Active::find($request->active_id);
foreach ($params as $key => $value) {
//入力フィールドにproposed_productというフィールドがあればループを抜ける(活動テーブルのフィールドに存在せずエラーとなる為)
if ($key === "proposed_product") {
continue;
}
$active->$key = $value;
}
// 更新されている項目があれば、更新ユーザIDをセットして保存
if ($active->isDirty()) {
$active->updated_user = Auth::user()->user_id;
$active->save();
}
//その活動に元々紐付いている提案商品のレコードを、リレーションを使用して取得
$original_proposed_products = $active->negotiation->proposed_products;
//リクエストで送られてくる提案商品のidの項目を配列に格納
$array_params = [];
foreach ($params['proposed_product'] as $param) {
//var_dump($original_proposed_product->proposed_product_id);
if (isset($param['proposed_product_id'])) {
$array_params[] = $param['proposed_product_id'];
}
}
//提案商品のidを,リレーションでDBから取得して配列に格納
$array_original_params = [];
foreach ($original_proposed_products as $original_proposed_product) {
$array_original_params[] = $original_proposed_product->proposed_product_id;
}
//その活動に元々紐付いていた提案商品のidと、送られてきた提案商品のidを比較して差分を取得。第一引数をベースにarray_diff関数を使用して比較。
$diff_params = array_diff($array_original_params, $array_params);
//リクエストで送られてこなかった提案商品IDをDBから取得し、$diff_paramsに格納。
foreach ($diff_params as $diff_param_id) {
$proposed_product = ProposedProduct::find($diff_param_id);
$true_flg = $proposed_product->delete();
//削除処理が成功した場合は、その内容をjsonレスポンスでフロント側に返却。
if ($true_flg) {
$deleted_proposed_product[] = $proposed_product;
$active->deleted_proposed_product = $deleted_proposed_product;
}
}
//既存の提案商品の更新処理
foreach ($params['proposed_product'] as $param) {
//リクエストで送られる入力フィールドに提案商品IDが存在せず、代わりに他の値が含まれている場合にはレコード登録処理をしたい
if (empty($param['proposed_product_id'])) {
if (!empty($param['general_product_id']) || !empty($param['broadcast_product_id']) || !empty($param['other_product_id'])) {
$created_proposed_products[] = ProposedProduct::create($param);
$active->created_proposed_products = $created_proposed_products;
}
//リクエストで送られてくる入力フィールドに提案商品IDが存在し、かつDBに登録されている提案商品IDと一致する場合はそのレコードの提案商品内容を更新する。
} else {
$proposed_product = ProposedProduct::find($param['proposed_product_id']);
foreach ($param as $key => $value) {
$proposed_product->$key = $value;
}
// 更新されている項目があれば、更新ユーザIDをセットして保存
if ($proposed_product->isDirty()) {
$proposed_product->updated_user = Auth::user()->user_id;
$true_flg = $proposed_product->save();
if ($true_flg === true) {
$updated_proposed_product[] = $proposed_product;
$active->updated_proposed_product = $updated_proposed_product;
}
}
}
}
} catch (Exception $e) {
Log::error(__METHOD__ . ' : ' . print_r($e->getMessage(), true));
DB::rollBack();
return $this->sendError(500, 'サーバエラーが発生しました');
}
DB::commit();
//リレーションで、自動的にレスポンスとして、その活動に紐付いている商談テーブルと提案商品のレコードが紐付いてしまうので、negotiation以下のオブジェクトを削除
unset($active["negotiation"]);
return $this->sendResponse($active);
}
改めて見返すと、まだまだコードをスマートに書ける部分があるなと感じておりますので
今後リファクタリングも行っていきます。
アドバイス等あればコメントでお待ちしております!宜しくお願い致します。