Add support for recording recipe volume (WIP)

This offers no practical value yet -- ultimately it will be used to support
volume-based servings for recipes with a total volume set.
This commit is contained in:
Christopher C. Wells 2021-04-17 20:31:52 -07:00
parent 6b68d61385
commit 809e3ca7d7
8 changed files with 69 additions and 5 deletions

View File

@ -201,6 +201,7 @@ class RecipeController extends Controller
'description_delta' => $input['description_delta'],
'servings' => (int) $input['servings'],
'weight' => $input['weight'],
'volume' => Number::floatFromString($input['volume']),
'time_prep' => (int) $input['time_prep'],
'time_cook' => (int) $input['time_cook'],
'source' => $input['source'],

View File

@ -24,7 +24,8 @@ class UpdateRecipeRequest extends FormRequest
'servings' => ['required', 'numeric'],
'time_prep' => ['nullable', 'numeric'],
'time_cook' => ['nullable', 'numeric'],
'weight' => ['nullable', 'numeric'],
'weight' => ['nullable', 'numeric', 'min:0'],
'volume' => ['nullable', new StringIsPositiveDecimalOrFraction],
'source' => ['nullable', 'string'],
'ingredients.amount' => ['required', 'array', new ArrayNotEmpty],
'ingredients.amount.*' => ['required_with:ingredients.id.*', 'nullable', new StringIsPositiveDecimalOrFraction],

View File

@ -36,6 +36,8 @@ class RecipeSchema extends SchemaProvider
'servings' => $resource->servings,
'weight' => $resource->weight,
'serving_weight' => $resource->serving_weight,
'volume' => $resource->volume,
'volumeFormatted' => $resource->volume_formatted,
'units_supported' => $resource->units_supported->pluck('label'),
'caloriesPerServing' => $resource->caloriesPerServing(),
'carbohydratesPerServing' => $resource->carbohydratesPerServing(),

View File

@ -7,6 +7,7 @@ use App\Models\Traits\Ingredient;
use App\Models\Traits\Journalable;
use App\Models\Traits\Sluggable;
use App\Models\Traits\Taggable;
use App\Support\Number;
use App\Support\Nutrients;
use ElasticScoutDriverPlus\QueryDsl;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -104,6 +105,7 @@ final class Recipe extends Model implements HasMedia
'source',
'servings',
'weight',
'volume',
];
/**
@ -114,6 +116,7 @@ final class Recipe extends Model implements HasMedia
'time_prep' => 'int',
'time_cook' => 'int',
'weight' => 'float',
'volume' => 'float',
];
/**
@ -133,6 +136,7 @@ final class Recipe extends Model implements HasMedia
*/
protected $appends = [
'serving_weight',
'volume_formatted',
'time_total',
'units_supported'
];
@ -169,6 +173,17 @@ final class Recipe extends Model implements HasMedia
return round($this->weight / $this->servings);
}
/**
* Get the volume as a formatted string (e.g. 0.5 = 1/2).
*/
public function getVolumeFormattedAttribute(): ?string {
$result = null;
if (!empty($this->volume)) {
$result = Number::rationalStringFromFloat($this->volume);
}
return $result;
}
/**
* Get the ingredients list (ingredient amounts and separators).
*/

View File

@ -23,6 +23,7 @@ class RecipeFactory extends Factory
public function definition(): array
{
$description = htmlspecialchars($this->faker->realText(500));
$volumes = [1/4, 1/3, 1/2, 2/3, 3/4, 1, 1 + 1/2, 1 + 3/4, 2, 2 + 1/2, 3, 3 + 1/2, 4, 5];
return [
'name' => Words::randomWords(Arr::random(['npan', 'npn', 'anpn'])),
'description' => "<p>{$description}</p>",
@ -31,7 +32,8 @@ class RecipeFactory extends Factory
'time_cook' => $this->faker->numberBetween(0, 90),
'source' => $this->faker->optional()->url,
'servings' => $this->faker->numberBetween(1, 10),
'weight' => $this->faker->randomFloat(1, 60, 2000),
'weight' => $this->faker->optional()->randomFloat(1, 60, 2000),
'volume' => $this->faker->optional()->randomElement($volumes),
'tags' => Words::randomWords(Arr::random(['a', 'aa', 'aaa']), TRUE),
];
}

View File

@ -24,6 +24,7 @@ class CreateRecipesTable extends Migration
$table->string('source')->nullable();
$table->unsignedInteger('servings');
$table->unsignedFloat('weight')->nullable();
//$table->decimal('volume', 10, 8)->unsigned()->nullable();
$table->timestamps();
});
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddVolumeToRecipes extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('recipes', function (Blueprint $table) {
$table->decimal('volume', 10, 8)->unsigned()->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('recipes', function (Blueprint $table) {
$table->dropColumn('volume');
});
}
}

View File

@ -33,7 +33,7 @@
<!-- Weight -->
<div class="flex-auto">
<x-inputs.label for="weight" value="Total weight (g)" />
<x-inputs.label for="weight" value="Weight (g)" />
<x-inputs.input name="weight"
type="number"
@ -42,9 +42,19 @@
:value="old('weight', $recipe->weight)" />
</div>
<!-- Volume -->
<div class="flex-auto">
<x-inputs.label for="volume" value="Volume (cups)" />
<x-inputs.input name="volume"
type="text"
class="block mt-1 w-full"
:value="old('volume', $recipe->volume_formatted)" />
</div>
<!-- Prep Time -->
<div class="flex-auto">
<x-inputs.label for="time_prep" value="Prep time (minutes)" />
<x-inputs.label for="time_prep" value="Prep time (min.)" />
<x-inputs.input name="time_prep"
type="number"
@ -56,7 +66,7 @@
<!-- Cooke Time -->
<div class="flex-auto">
<x-inputs.label for="time_cook" value="Cook time (minutes)" />
<x-inputs.label for="time_cook" value="Cook time (min.)" />
<x-inputs.input name="time_cook"
type="number"