Refactor on servings-based food data (WIP)

This commit is contained in:
Christopher C. Wells 2020-12-31 14:59:05 -08:00
parent 1ec4439d8e
commit c33776155a
6 changed files with 212 additions and 73 deletions

View File

@ -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',
];
}

View File

@ -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;
}
}

View File

@ -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();
});
}

View File

@ -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();

View File

@ -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);

View File

@ -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);
}
}