Add handling for recipes by weight in ingredient amounts and journal entries

This commit is contained in:
Christopher C. Wells 2021-02-11 20:25:36 -08:00
parent 836c40abf2
commit 33a8591c72
5 changed files with 75 additions and 18 deletions

View File

@ -135,7 +135,12 @@ class JournalEntryController extends Controller
elseif ($ingredient['type'] == Recipe::class) {
$item = Recipe::whereId($ingredient['id'])->first();
foreach (Nutrients::$all as $nutrient) {
$entries[$entry_key]->{$nutrient['value']} += $item->{"{$nutrient['value']}PerServing"}() * Number::floatFromString($ingredient['amount']);
$entries[$entry_key]->{$nutrient['value']} += Nutrients::calculateRecipeNutrientAmount(
$item,
$nutrient['value'],
Number::floatFromString($ingredient['amount']),
$ingredient['unit']
);
}
$entries[$entry_key]->recipes->add($item);
}
@ -144,14 +149,14 @@ class JournalEntryController extends Controller
}
// Update summary
if (empty($item->serving_unit) && empty($item->serving_unit_name)) {
$unit = null;
}
elseif (!empty($item->serving_unit_name)) {
$unit = $item->serving_unit_formatted;
}
else {
$unit = $ingredient['unit'];
$unit = $ingredient['unit'];
if ($item instanceof Food) {
if (empty($item->serving_unit) && empty($item->serving_unit_name)) {
$unit = null;
}
elseif (!empty($item->serving_unit_name)) {
$unit = $item->serving_unit_formatted;
}
}
$entries[$entry_key]->summary .= (!empty($entries[$entry_key]->summary) ? ', ' : null);
$entries[$entry_key]->summary .= "{$ingredient['amount']} {$unit} {$item->name}";

View File

@ -146,7 +146,12 @@ final class IngredientAmount extends Model
$this->amount,
$this->unit
),
Recipe::class => $this->ingredient->{"{$method}PerServing"}() * $this->amount,
Recipe::class => Nutrients::calculateRecipeNutrientAmount(
$this->ingredient,
$method,
$this->amount,
$this->unit
),
default => 0
};
}

View File

@ -53,6 +53,9 @@ use Spatie\Tags\HasTags;
* @method static \Illuminate\Database\Eloquent\Builder|Recipe withAllTagsOfAnyType($tags)
* @method static \Illuminate\Database\Eloquent\Builder|Recipe withAnyTags($tags, ?string $type = null)
* @method static \Illuminate\Database\Eloquent\Builder|Recipe withAnyTagsOfAnyType($tags)
* @property float|null $weight
* @property-read float|null $serving_weight
* @method static \Illuminate\Database\Eloquent\Builder|Recipe whereWeight($value)
*/
final class Recipe extends Model
{

View File

@ -3,12 +3,12 @@
namespace App\Support;
use App\Models\Food;
use App\Models\Recipe;
/**
* TODO: Refactor for more general use.
*/
class Nutrients
{
public static float $gramsPerOunce = 28.349523125;
public static array $all = [
['value' => 'calories', 'unit' => null],
['value' => 'fat', 'unit' => 'g'],
@ -27,13 +27,22 @@ class Nutrients
['value' => 'serving', 'label' => 'servings'],
];
/**
* Calculate a nutrient multiplier for a Food.
*
* @param \App\Models\Food $food
* @param float $amount
* @param string|null $fromUnit
*
* @return float
*/
public static function calculateFoodNutrientMultiplier(
Food $food,
float $amount,
string|null $fromUnit
): float {
if ($fromUnit === 'oz') {
return $amount * 28.349523125 / $food->serving_weight;
return $amount * self::$gramsPerOunce / $food->serving_weight;
}
elseif ($fromUnit === 'serving') {
return $amount;
@ -76,4 +85,34 @@ class Nutrients
return $multiplier / $food->serving_size * $amount;
}
/**
* Calculate a nutrient amount for a recipe.
*
* @param \App\Models\Recipe $recipe
* @param string $nutrient
* @param float $amount
* @param string $fromUnit
*
* @return float
*/
public static function calculateRecipeNutrientAmount(
Recipe $recipe,
string $nutrient,
float $amount,
string $fromUnit
): float {
if ($fromUnit === 'oz') {
return $amount * self::$gramsPerOunce / $recipe->weight * $recipe->{"{$nutrient}Total"}();
}
elseif ($fromUnit === 'serving') {
return $recipe->{"{$nutrient}PerServing"}() * $amount;
}
elseif ($fromUnit === 'gram') {
return $amount / $recipe->weight * $recipe->{"{$nutrient}Total"}();
}
else {
throw new \DomainException("Unsupported recipe unit: {$fromUnit}");
}
}
}

View File

@ -29,12 +29,17 @@
x-bind:data-detail="result.detail">
<div class="pointer-events-none">
<div>
<span x-text="result.name"></span><span class="text-gray-600" x-text="', ' + result.detail" x-show="result.detail"></span>
<span class="font-bold" x-text="result.name"></span><span class="text-gray-600" x-text="', ' + result.detail" x-show="result.detail"></span>
</div>
<div x-show="result.servings">
<div class="text-sm">Servings: <span x-text="result.servings"></span></div>
<div x-show="result.type === 'App\\Models\\Recipe'">
<div x-show="result.serving_weight">
<div class="text-sm">Serving weight <span x-text="result.serving_weight"></span>g</div>
</div>
<div x-show="result.servings">
<div class="text-sm">Servings: <span x-text="result.servings"></span></div>
</div>
</div>
<div x-show="result.serving_size">
<div x-show="result.type === 'App\\Models\\Food'">
<div class="text-sm text-gray-600" x-text="result.brand" x-show="result.brand"></div>
<div class="text-sm">
Serving size <span x-text="result.serving_size_formatted"></span>