mirror of https://github.com/kcal-app/kcal.git
Refactor on servings-based food data (WIP)
This commit is contained in:
parent
1ec4439d8e
commit
c33776155a
|
|
@ -9,14 +9,16 @@ use Illuminate\Database\Eloquent\Model;
|
|||
* @property int id
|
||||
* @property string name Food base name.
|
||||
* @property ?string detail Some additional detail about the food (e.g. "small" with the name "onion").
|
||||
* @property float carbohydrates (per 100g).
|
||||
* @property float calories (per 100g).
|
||||
* @property float cholesterol (per 100g).
|
||||
* @property float fat (per 100g).
|
||||
* @property float protein (per 100g).
|
||||
* @property float sodium (per 100g).
|
||||
* @property ?float unit_weight Weight of one cup of the food.
|
||||
* @property ?float cup_weight Weight of one "unit" (e.g. an egg, onion, etc.) of the food.
|
||||
* @property ?string brand Brand name.
|
||||
* @property float carbohydrates per serving (g).
|
||||
* @property float calories per serving (g).
|
||||
* @property float cholesterol per serving (g).
|
||||
* @property float fat per serving (g).
|
||||
* @property float protein per serving (g).
|
||||
* @property float sodium per serving (g).
|
||||
* @property float serving_size Size of one serving of the food.
|
||||
* @property ?string serving_unit Unit for serving weight (tsp, tbsp, cup, or null).
|
||||
* @property float serving_weight per serving (g).
|
||||
* @property \Illuminate\Support\Carbon created_at
|
||||
* @property \Illuminate\Support\Carbon updated_at
|
||||
*/
|
||||
|
|
@ -35,14 +37,16 @@ class Food extends Model
|
|||
protected $fillable = [
|
||||
'name',
|
||||
'detail',
|
||||
'brand',
|
||||
'calories',
|
||||
'carbohydrates',
|
||||
'cholesterol',
|
||||
'fat',
|
||||
'protein',
|
||||
'sodium',
|
||||
'unit_weight',
|
||||
'cup_weight',
|
||||
'serving_size',
|
||||
'serving_unit',
|
||||
'serving_weight',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -52,10 +56,10 @@ class Food extends Model
|
|||
'calories' => 'float',
|
||||
'carbohydrates' => 'float',
|
||||
'cholesterol' => 'float',
|
||||
'cup_weight' => 'float',
|
||||
'fat' => 'float',
|
||||
'protein' => 'float',
|
||||
'serving_size' => 'float',
|
||||
'serving_weight' => 'float',
|
||||
'sodium' => 'float',
|
||||
'unit_weight' => 'float',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,19 +94,38 @@ class FoodAmount extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the multiplier for the food unit based on weight.
|
||||
*
|
||||
* Unit weight will be specified for foods that are added by unit
|
||||
* (e.g. eggs, vegetables, etc.) and cup weight (the weight of the
|
||||
* food equal to one cup) will be specified for foods that are
|
||||
* measured (e.g. flour, milk, etc.).
|
||||
* Get the multiplier for nutrient calculations based on serving data.
|
||||
*/
|
||||
private function unitMultiplier(): float {
|
||||
return match ($this->unit) {
|
||||
null => $this->food->unit_weight,
|
||||
'tsp' => 1/48,
|
||||
'tbsp' => 1/16,
|
||||
default => 1
|
||||
} * $this->amount * ($this->food->cup_weight ?? 1) / 100;
|
||||
if ($this->unit === 'oz') {
|
||||
return $this->amount * 28.349523125 / $this->food->serving_weight;
|
||||
}
|
||||
|
||||
if ($this->food->serving_unit === $this->unit) {
|
||||
$multiplier = 1;
|
||||
}
|
||||
elseif ($this->unit === 'tsp') {
|
||||
$multiplier = match ($this->food->serving_unit) {
|
||||
'tbsp' => 1/3,
|
||||
'cup' => 1/48,
|
||||
};
|
||||
}
|
||||
elseif ($this->unit === 'tbsp') {
|
||||
$multiplier = match ($this->food->serving_unit) {
|
||||
'tsp' => 3,
|
||||
'cup' => 1/16,
|
||||
};
|
||||
}
|
||||
elseif ($this->unit === 'cup') {
|
||||
$multiplier = match ($this->food->serving_unit) {
|
||||
'tsp' => 48,
|
||||
'tbsp' => 16,
|
||||
};
|
||||
}
|
||||
else {
|
||||
throw new \DomainException("Unhandled unit combination: {$this->unit}, {$this->food->serving_unit}");
|
||||
}
|
||||
|
||||
return $multiplier / $this->food->serving_size * $this->amount;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,16 @@ class CreateFoodsTable extends Migration
|
|||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('detail')->nullable();
|
||||
$table->string('brand')->nullable();
|
||||
$table->unsignedFloat('serving_size');
|
||||
$table->enum('serving_unit', ['tsp', 'tbsp', 'cup', 'oz'])->nullable();
|
||||
$table->unsignedFloat('serving_weight');
|
||||
$table->unsignedFloat('calories')->default(0);
|
||||
$table->unsignedFloat('carbohydrates')->default(0);
|
||||
$table->unsignedFloat('cholesterol')->default(0);
|
||||
$table->unsignedFloat('fat')->default(0);
|
||||
$table->unsignedFloat('protein')->default(0);
|
||||
$table->unsignedFloat('cholesterol')->default(0);
|
||||
$table->unsignedFloat('sodium')->default(0);
|
||||
$table->unsignedFloat('unit_weight')->nullable();
|
||||
$table->unsignedFloat('cup_weight')->nullable();
|
||||
$table->unsignedFloat('carbohydrates')->default(0);
|
||||
$table->unsignedFloat('protein')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class CreateFoodAmountsTable extends Migration
|
|||
$table->id();
|
||||
$table->foreignIdFor(Food::class);
|
||||
$table->unsignedFloat('amount');
|
||||
$table->enum('unit', ['tsp', 'tbsp', 'cup', 'grams'])->nullable();
|
||||
$table->enum('unit', ['tsp', 'tbsp', 'cup', 'oz'])->nullable();
|
||||
$table->foreignIdFor(Recipe::class);
|
||||
$table->unsignedInteger('weight');
|
||||
$table->timestamps();
|
||||
|
|
|
|||
|
|
@ -15,74 +15,146 @@ class FoodSeeder extends Seeder
|
|||
$default_foods = [
|
||||
[
|
||||
'name' => 'baking powder',
|
||||
'calories' => 53,
|
||||
'carbohydrates' => 27.7,
|
||||
'sodium' => 10.6,
|
||||
'cup_weight' => 220.8,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'tsp',
|
||||
'serving_weight' => 4.6,
|
||||
'calories' => 2.44,
|
||||
'fat' => 0,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0.488,
|
||||
'carbohydrates' => 1.27,
|
||||
'protein' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'egg',
|
||||
'detail' => 'large',
|
||||
'calories' => 147,
|
||||
'carbohydrates' => 0.96,
|
||||
'cholesterol' => 0.411,
|
||||
'fat' => 9.96,
|
||||
'protein' => 12.4,
|
||||
'sodium' => 0.129,
|
||||
'unit_weight' => 50.3,
|
||||
'serving_size' => 1,
|
||||
'serving_weight' => 50.3,
|
||||
'calories' => 71.9,
|
||||
'fat' => 5.01,
|
||||
'cholesterol' => 0.207,
|
||||
'sodium' => 0.0649,
|
||||
'carbohydrates' => 0.483,
|
||||
'protein' => 6.24,
|
||||
],
|
||||
[
|
||||
'name' => 'flour',
|
||||
'detail' => 'all-purpose',
|
||||
'calories' => 364,
|
||||
'carbohydrates' => 76.31,
|
||||
'fat' => 0.98,
|
||||
'protein' => 10.33,
|
||||
'sodium' => 0.004,
|
||||
'cup_weight' => 125,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 125,
|
||||
'calories' => 455,
|
||||
'fat' => 1.22,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0.0025,
|
||||
'carbohydrates' => 95.4,
|
||||
'protein' => 12.9,
|
||||
],
|
||||
[
|
||||
'name' => 'milk',
|
||||
'detail' => 'whole',
|
||||
'calories' => 60,
|
||||
'carbohydrates' => 4.67,
|
||||
'cholesterol' => 0.012,
|
||||
'fat' => 3.2,
|
||||
'protein' => 3.28,
|
||||
'sodium' => 0.038,
|
||||
'cup_weight' => 244,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 244,
|
||||
'calories' => 146,
|
||||
'fat' => 7.81,
|
||||
'cholesterol' => 0.0293,
|
||||
'sodium' => 0.0927,
|
||||
'carbohydrates' => 11.4,
|
||||
'protein' => 8,
|
||||
],
|
||||
[
|
||||
'name' => 'salt',
|
||||
'detail' => 'table',
|
||||
'sodium' => 38.758,
|
||||
'cup_weight' => 292,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'tsp',
|
||||
'serving_weight' => 6,
|
||||
'calories' => 0,
|
||||
'fat' => 0,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 2.33,
|
||||
'carbohydrates' => 0,
|
||||
'protein' => 0,
|
||||
|
||||
],
|
||||
[
|
||||
'name' => 'sugar',
|
||||
'detail' => 'white',
|
||||
'calories' => 385,
|
||||
'carbohydrates' => 99.6,
|
||||
'fat' => 0.32,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 200,
|
||||
'calories' => 770,
|
||||
'fat' => 0.64,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0.002,
|
||||
'carbohydrates' => 199,
|
||||
'protein' => 0,
|
||||
'sodium' => 0.001,
|
||||
'cup_weight' => 200,
|
||||
],
|
||||
[
|
||||
'name' => 'vegetable oil',
|
||||
'calories' => 886,
|
||||
'fat' => 100,
|
||||
'cup_weight' => 224,
|
||||
'serving_size' => 1,
|
||||
'serving_unit' => 'tbsp',
|
||||
'serving_weight' => 14,
|
||||
'calories' => 124,
|
||||
'fat' => 14,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0,
|
||||
'carbohydrates' => 0,
|
||||
'protein' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'peanut butter',
|
||||
'detail' => 'Kirkland organic creamy',
|
||||
'calories' => 562.5,
|
||||
'fat' => 46.875,
|
||||
'sodium' => 0.203125,
|
||||
'carbohydrates' => 21.875,
|
||||
'protein' => 25,
|
||||
'cup_weight' => 256,
|
||||
'detail' => 'organic creamy',
|
||||
'brand' => 'Kirkland',
|
||||
'serving_size' => 2,
|
||||
'serving_unit' => 'tbsp',
|
||||
'serving_weight' => 32,
|
||||
'calories' => 180,
|
||||
'fat' => 15,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0.065,
|
||||
'carbohydrates' => 7,
|
||||
'protein' => 8,
|
||||
],
|
||||
[
|
||||
'name' => 'raisins',
|
||||
'brand' => 'Kroger',
|
||||
'serving_size' => 0.25,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 40,
|
||||
'calories' => 140,
|
||||
'fat' => 0,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0.010,
|
||||
'carbohydrates' => 33,
|
||||
'protein' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'peanuts',
|
||||
'detail' => 'dry roasted, unsalted',
|
||||
'brand' => 'Kroger',
|
||||
'serving_size' => 0.25,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 28,
|
||||
'calories' => 160,
|
||||
'fat' => 14,
|
||||
'cholesterol' => 0,
|
||||
'sodium' => 0,
|
||||
'carbohydrates' => 6,
|
||||
'protein' => 7,
|
||||
],
|
||||
[
|
||||
'name' => 'canned corn',
|
||||
'detail' => 'golden sweet',
|
||||
'brand' => 'WinCo',
|
||||
'serving_size' => 0.5,
|
||||
'serving_unit' => 'cup',
|
||||
'serving_weight' => 125,
|
||||
'calories' => 60,
|
||||
'fat' => 0.5,
|
||||
'sodium' => 0.2,
|
||||
'carbohydrates' => 9,
|
||||
'protein' => 1,
|
||||
],
|
||||
];
|
||||
Food::factory()->createMany($default_foods);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ class RecipeSeeder extends Seeder
|
|||
[
|
||||
'food_id' => Food::where('name', 'flour')
|
||||
->first()->id,
|
||||
'amount' => 1,
|
||||
'unit' => 'cup',
|
||||
'amount' => 4.25,
|
||||
'unit' => 'oz',
|
||||
'recipe_id' => $recipe->id,
|
||||
'weight' => $weight++,
|
||||
],
|
||||
|
|
@ -95,5 +95,47 @@ class RecipeSeeder extends Seeder
|
|||
]
|
||||
];
|
||||
RecipeStep::factory()->createMany($steps);
|
||||
|
||||
/** @var \App\Models\Recipe $recipe */
|
||||
$recipe = Recipe::factory()->create([
|
||||
'name' => 'peanut butter corn',
|
||||
'description' => 'Peanut butter and corn -- YUM',
|
||||
'servings' => 4,
|
||||
]);
|
||||
|
||||
$weight = 0;
|
||||
$amounts = [
|
||||
[
|
||||
'food_id' => Food::where('name', 'peanut butter')
|
||||
->first()->id,
|
||||
'amount' => 2,
|
||||
'unit' => 'cup',
|
||||
'recipe_id' => $recipe->id,
|
||||
'weight' => $weight++,
|
||||
],
|
||||
[
|
||||
'food_id' => Food::where('name', 'canned corn')
|
||||
->first()->id,
|
||||
'amount' => 15.25,
|
||||
'unit' => 'oz',
|
||||
'recipe_id' => $recipe->id,
|
||||
'weight' => $weight++,
|
||||
],
|
||||
];
|
||||
FoodAmount::factory()->createMany($amounts);
|
||||
|
||||
$steps = [
|
||||
[
|
||||
'recipe_id' => $recipe->id,
|
||||
'number' => 1,
|
||||
'step' => 'Mix it together.',
|
||||
],
|
||||
[
|
||||
'recipe_id' => $recipe->id,
|
||||
'number' => 2,
|
||||
'step' => 'Eat it.',
|
||||
]
|
||||
];
|
||||
RecipeStep::factory()->createMany($steps);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue