ユーザーが入力したカラムを使って、同テーブルの別カラムに値を入れたい
Railsを書いていた頃は、モデルにbefore_save
メソッドを書いて
そこに計算式などを書いていたのだが、Laravelの場合どのように書くとやりたいことができるのか??
例えば、ユーザーがheight
とweight
を入力したとして、
その値をシステムが計算し、basemetabolism
というカラムに値を自動で入れてくれる場合、
Railsだと下記のようにモデルに記載することで実装できる。
(そもそもこれがベストプラクティスかはわからない)
before_save do
self.basemetabolism = 13.397*(weight)+4.799*(height)-5.677*(user.age)+88.362
end
同様のやり方でLaravelでもできないかなと思ったのですが、
いまいちしっくりこなかったので、一次避難としてコントローラに直接計算式を書いてしまうことにしました。
実際のコード(Laravel)
public function store(IdealWeightRequest $request) {
$idealWeight = new IdealWeight();
$idealWeight->basal_metabolism = 13.397*($idealWeight->weight)+4.799*($idealWeight->height)-5.677*(Auth::user()->age)+88.362;
}
カラムが1つだけならまだいいですが、
多くなってくるとコントローラの可読性が下がるため他にいい方法ないかなと思っています。
一旦問題なく動いてはいるので最優先ではないですが、
なにか良い方法がありましたらコメントいただけますと助かりますm(_ _)m
追記
モデルに以下を記載し、fillableを使ってまとめてコントローラでsaveをすることで
コントローラの記述をスッキリさせることができました!
@sgrs38 さんアドバイスありがとうございます!
IdealWeightController
public function store(IdealWeightRequest $request) {
$validated = $request->safe()->only([
'height',
'weight',
'target_weight',
'exercise_level',
'start_day',
'last_day',
]);
$idealWeight = new IdealWeight();
$idealWeight->user_id = Auth::id();
$idealWeight->fill($request->all())->save();
return redirect()->route('idealweights.index')->with(
'message', '基本情報の入力が完了したので、次に目標を登録しましょう'
);
}
IdealWeight.php
class IdealWeight extends Model
{
use HasFactory;
protected $fillable = ['height','weight','target_weight', 'exercise_level', 'period', 'basal_metabolism', 'calories_burned', 'minus_weight', 'minus_calories', 'calories_intake', 'protein_gram_intake', 'protein_calories_intake', 'fat_gram_intake', 'fat_calories_intake', 'carbo_gram_intake', 'carbo_calories_intake', 'start_day', 'last_day', 'minus_weight_day'];
public static function boot()
{
parent::boot();
self::saving(function (IdealWeight $idealWeight) {
// ボディメイク期間
$idealWeight->period = Carbon::create($idealWeight->last_day)->diffInDays(Carbon::create($idealWeight->start_day));
// 基礎代謝
if (Auth::user()->gender === "男") {
$idealWeight->basal_metabolism = 13.397*($idealWeight->weight)+4.799*($idealWeight->height)-5.677*(Auth::user()->age)+88.362; #男性の場合
} else {
$idealWeight->basal_metabolism = 9.247*($idealWeight->weight)+3.098*($idealWeight->height)-4.33*(Auth::user()->age)+447.593; #女性の場合
}
// 消費カロリー
$idealWeight->calories_burned = ($idealWeight->basal_metabolism)*($idealWeight->exercise_level);
// 何キロ落とすか
$idealWeight->minus_weight = ($idealWeight->weight)-($idealWeight->target_weight);
// 何キロカロリー落とすか
$idealWeight->minus_calories = ($idealWeight->minus_weight)*7200;
// 1日あたり何キロ落とせば良いか
$idealWeight->minus_weight_day = ($idealWeight->minus_weight)/($idealWeight->period);
// 1日あたり何キロカロリー摂取すればいいか
$idealWeight->calories_intake = ($idealWeight->calories_burned)-($idealWeight->minus_calories)/($idealWeight->period);
// タンパク質摂取量(g)
if ($idealWeight->exercise_level === '1.9') {
$idealWeight->protein_gram_intake = ($idealWeight->weight) * 2;
} elseif ($idealWeight->exercise_level === '1.73') {
$idealWeight->protein_gram_intake = ($idealWeight->weight) * 1.8;
} elseif ($idealWeight->exercise_level === '1.55') {
$idealWeight->protein_gram_intake = ($idealWeight->weight) * 1.4;
} elseif ($idealWeight->exercise_level === '1.38') {
$idealWeight->protein_gram_intake = ($idealWeight->weight) * 1;
} elseif ($idealWeight->exercise_level === '1.2') {
$idealWeight->protein_gram_intake = ($idealWeight->weight) * 0.8;
}
// タンパク質摂取カロリー(g*4g)
$idealWeight->protein_calories_intake = ($idealWeight->protein_gram_intake)*4;
// 脂質摂取カロリー
$idealWeight->fat_calories_intake = ($idealWeight->calories_intake)*0.2;
// 脂質摂取量(g)
$idealWeight->fat_gram_intake = ($idealWeight->fat_calories_intake)/9;
// 炭水化物摂取カロリー
$idealWeight->carbo_calories_intake = ($idealWeight->calories_intake)-($idealWeight->protein_calories_intake)-($idealWeight->fat_calories_intake);
// 炭水化物摂取量(g)
$idealWeight->carbo_gram_intake = ($idealWeight->carbo_calories_intake)/4;
});
}
}
実はこんなに長かったカラム間で計算したい記述。。
これがベストプラクティスかは再度わからないですが、コントローラがスッキリしたので
以前よりはかなり可読性もあがってよかったですm(_ _)m