'float', 'weight' => 'int', ]; /** * Nutrient calculation methods. */ private array $nutrientMethods = [ 'calories', 'carbohydrates', 'cholesterol', 'fat', 'protein', 'sodium', ]; /** * @inheritdoc */ protected $appends = [ 'amount_formatted', 'nutrients_summary', 'unit_formatted' ]; /** * Get the amount as a formatted string (e.g. 0.5 = 1/2). */ public function getAmountFormattedAttribute(): string { return Number::rationalStringFromFloat($this->amount); } /** * Get a simple string summary of nutrients for the ingredient amount. * * TODO: Move to HasIngredients trait. */ public function getNutrientsSummaryAttribute(): string { $summary = []; foreach (Nutrients::all() as $nutrient) { $amount = Nutrients::round($this->{$nutrient['value']}(), $nutrient['value']); $summary[] = "{$nutrient['label']}: {$amount}{$nutrient['unit']}"; } return implode(', ', $summary); } /** * Get a "formatted" unit. * * @see \App\Models\Food::getServingUnitFormattedAttribute() */ public function getUnitFormattedAttribute(): ?string { $unit = $this->unit; // Inherit formatted unit from Food. if ($unit === 'serving' && $this->ingredient->type === Food::class) { $unit = $this->ingredient->serving_unit_formatted; } if ($unit && $unit != 'tsp' && $unit != 'tbsp'&& $unit != 'oz') { $unit = Pluralizer::plural($unit, ceil($this->amount)); } return $unit; } /** * Get the ingredient type (Food or Recipe). */ public function ingredient(): BelongsTo { return $this->morphTo(); } /** * Get the parent (Recipe or JournalEntry). */ public function parent(): BelongsTo { return $this->morphTo(); } /** * Add nutrient calculations handling to overloading. * * @param string $method * @param array $parameters * * @return mixed */ public function __call($method, $parameters): mixed { if (in_array($method, $this->nutrientMethods)) { return match ($this->ingredient::class) { Food::class => $this->ingredient->{$method} * Nutrients::calculateFoodNutrientMultiplier( $this->ingredient, $this->amount, $this->unit ), Recipe::class => Nutrients::calculateRecipeNutrientAmount( $this->ingredient, $method, $this->amount, $this->unit ), default => 0 }; } else { return parent::__call($method, $parameters); } } }