Refactor journal entries to record nutrients directly

This commit is contained in:
Christopher C. Wells 2021-01-01 09:39:13 -08:00
parent dd40582b64
commit dfad48c71d
9 changed files with 184 additions and 52 deletions

View File

@ -3,7 +3,6 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* @property int id
@ -22,7 +21,7 @@ use Illuminate\Database\Eloquent\Model;
* @property \Illuminate\Support\Carbon created_at
* @property \Illuminate\Support\Carbon updated_at
*/
class Food extends Model
class Food extends JournalableModel
{
use HasFactory;

View File

@ -5,9 +5,19 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
/**
* TODO: Change this model to track nutrients _directly_.
* @property int id
* @property \Illuminate\Support\Carbon date
* @property string summary
* @property float calories
* @property float carbohydrates
* @property float cholesterol
* @property float fat
* @property float protein
* @property float sodium
* @property string meal
*/
class JournalEntry extends Model
{
@ -17,38 +27,34 @@ class JournalEntry extends Model
* @inheritdoc
*/
protected $fillable = [
'calories',
'carbohydrates',
'cholesterol',
'date',
'servings',
'amount',
'unit',
'fat',
'meal',
'protein',
'sodium',
'summary',
];
/**
* The attributes that should be cast.
*/
protected $casts = [
'calories' => 'float',
'carbohydrates' => 'float',
'cholesterol' => 'float',
'date' => 'datetime:Y-m-d',
'amount' => 'float',
'fat' => 'float',
'protein' => 'float',
'sodium' => 'float',
];
/**
* @inheritdoc
*/
protected $with = ['recipe', 'food', 'user'];
/**
* Get the Recipe this entry belongs to.
*/
public function recipe(): BelongsTo {
return $this->belongsTo(Recipe::class);
}
/**
* Get the Food this entry belongs to.
*/
public function food(): BelongsTo {
return $this->belongsTo(Food::class);
}
protected $with = ['user', 'foods', 'recipes'];
/**
* Get the User this entry belongs to.
@ -57,4 +63,18 @@ class JournalEntry extends Model
return $this->belongsTo(User::class);
}
/**
* Get all recipes related to this entry.
*/
public function foods(): MorphToMany {
return $this->morphedByMany(Food::class, 'journalable');
}
/**
* Get all recipes related to this entry.
*/
public function recipes(): MorphToMany {
return $this->morphedByMany(Recipe::class, 'journalable');
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
abstract class JournalableModel extends Model
{
/**
* Get all of the journal entries for the recipe.
*/
public function journalEntries(): MorphToMany {
return $this->morphToMany(JournalEntry::class, 'journalable');
}
}

View File

@ -3,7 +3,6 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
@ -28,7 +27,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
* @method float sodiumTotal Get total sodium.
* @method float sodiumPerServing Get per serving sodium.
*/
class Recipe extends Model
class Recipe extends JournalableModel
{
use HasFactory;

View File

@ -17,10 +17,10 @@ class CreateFoodAmountsTable extends Migration
{
Schema::create('food_amounts', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Food::class);
$table->foreignIdFor(Food::class)->index();
$table->unsignedFloat('amount');
$table->enum('unit', ['tsp', 'tbsp', 'cup', 'oz'])->nullable();
$table->foreignIdFor(Recipe::class);
$table->foreignIdFor(Recipe::class)->index();
$table->unsignedInteger('weight');
$table->timestamps();
});

View File

@ -20,6 +20,7 @@ class CreateRecipeStepsTable extends Migration
$table->unsignedInteger('number');
$table->longText('step');
$table->timestamps();
$table->index('recipe_id', 'number');
});
}

View File

@ -1,7 +1,5 @@
<?php
use App\Models\Food;
use App\Models\Recipe;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
@ -19,13 +17,17 @@ class CreateJournalEntriesTable extends Migration
Schema::create('journal_entries', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class);
$table->foreignIdFor(Food::class)->nullable();
$table->foreignIdFor(Recipe::class)->nullable();
$table->date('date')->useCurrent();
$table->unsignedFloat('amount');
$table->enum('unit', ['tsp', 'tbsp', 'cup', 'grams', 'serving'])->nullable();
$table->string('summary');
$table->unsignedFloat('calories')->default(0);
$table->unsignedFloat('fat')->default(0);
$table->unsignedFloat('cholesterol')->default(0);
$table->unsignedFloat('sodium')->default(0);
$table->unsignedFloat('carbohydrates')->default(0);
$table->unsignedFloat('protein')->default(0);
$table->enum('meal', ['breakfast', 'lunch', 'dinner', 'snacks']);
$table->timestamps();
$table->index(['user_id', 'date']);
});
}

View File

@ -0,0 +1,33 @@
<?php
use App\Models\JournalEntry;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJournalablesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('journalables', function (Blueprint $table) {
$table->foreignIdFor(JournalEntry::class)->index();
$table->unsignedInteger('journalable_id');
$table->string('journalable_type');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('journalables');
}
}

View File

@ -6,8 +6,9 @@ use App\Models\Food;
use App\Models\JournalEntry;
use App\Models\Recipe;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class JournalEntrySeeder extends Seeder
{
@ -18,49 +19,110 @@ class JournalEntrySeeder extends Seeder
*/
public function run()
{
/** @var \App\Models\Food[] $foods */
foreach (['peanut butter', 'milk', 'egg', 'raisins'] as $name) {
$foods[$name] = Food::where('name', $name)->first();
}
/** @var \App\Models\Recipe $recipe */
$recipe = Recipe::all()->first();
/** @var \App\Models\User $user */
$user = User::all()->first;
$default_entries = [
[
'user_id' => $user->id,
'food_id' => Food::where('name', 'milk')->first()->id,
'date' => Carbon::now()->toDateString(),
'amount' => 2,
'unit' => 'cup',
'summary' => '2 egg, 1 serving milk',
'calories' => $foods['egg']->calories * 2 + $foods['milk']->calories,
'fat' => $foods['egg']->fat * 2 + $foods['milk']->fat,
'cholesterol' => $foods['egg']->cholesterol * 2 + $foods['milk']->cholesterol,
'sodium' => $foods['egg']->sodium * 2 + $foods['milk']->sodium,
'carbohydrates' => $foods['egg']->carbohydrates * 2 + $foods['milk']->carbohydrates,
'protein' => $foods['egg']->protein * 2 + $foods['milk']->protein,
'meal' => 'breakfast',
],
[
'user_id' => $user->id,
'food_id' => Food::where('name', 'egg')->first()->id,
'date' => Carbon::now()->toDateString(),
'amount' => 3,
'meal' => 'breakfast',
],
[
'user_id' => $user->id,
'recipe_id' => Recipe::all()->first(),
'date' => Carbon::now()->toDateString(),
'amount' => 1,
'unit' => 'serving',
'summary' => '1 serving pancakes',
'calories' => $recipe->caloriesPerServing(),
'fat' => $recipe->fatPerServing(),
'cholesterol' => $recipe->cholesterolPerServing(),
'sodium' => $recipe->sodiumPerServing(),
'carbohydrates' => $recipe->carbohydratesPerServing(),
'protein' => $recipe->proteinPerServing(),
'meal' => 'lunch',
],
[
'user_id' => $user->id,
'recipe_id' => Recipe::all()->first(),
'date' => Carbon::now()->toDateString(),
'amount' => 1.5,
'unit' => 'serving',
'summary' => '1 serving pancakes',
'calories' => $recipe->caloriesPerServing(),
'fat' => $recipe->fatPerServing(),
'cholesterol' => $recipe->cholesterolPerServing(),
'sodium' => $recipe->sodiumPerServing(),
'carbohydrates' => $recipe->carbohydratesPerServing(),
'protein' => $recipe->proteinPerServing(),
'meal' => 'dinner',
],
[
'user_id' => $user->id,
'food_id' => Food::where('name', 'peanut butter')->first()->id,
'date' => Carbon::now()->toDateString(),
'amount' => 2,
'unit' => 'tbsp',
'summary' => '1 serving peanut butter',
'calories' => $foods['peanut butter']->calories,
'fat' => $foods['peanut butter']->fat,
'cholesterol' => $foods['peanut butter']->cholesterol,
'sodium' => $foods['peanut butter']->sodium,
'carbohydrates' => $foods['peanut butter']->carbohydrates,
'protein' => $foods['peanut butter']->protein,
'meal' => 'snacks',
],
[
'user_id' => $user->id,
'date' => Carbon::now()->toDateString(),
'summary' => '2 servings raisins',
'calories' => $foods['raisins']->calories * 2,
'fat' => $foods['raisins']->fat * 2,
'cholesterol' => $foods['raisins']->cholesterol * 2,
'sodium' => $foods['raisins']->sodium * 2,
'carbohydrates' => $foods['raisins']->carbohydrates * 2,
'protein' => $foods['raisins']->protein * 2,
'meal' => 'snacks',
],
];
JournalEntry::factory()->createMany($default_entries);
DB::table('journalables')->insert([
'journal_entry_id' => 1,
'journalable_id' => $foods['egg']->id,
'journalable_type' => Food::class,
]);
DB::table('journalables')->insert([
'journal_entry_id' => 1,
'journalable_id' => $foods['milk']->id,
'journalable_type' => Food::class,
]);
DB::table('journalables')->insert([
'journal_entry_id' => 2,
'journalable_id' => $recipe->id,
'journalable_type' => Recipe::class,
]);
DB::table('journalables')->insert([
'journal_entry_id' => 3,
'journalable_id' => $recipe->id,
'journalable_type' => Recipe::class,
]);
DB::table('journalables')->insert([
'journal_entry_id' => 4,
'journalable_id' => $foods['peanut butter']->id,
'journalable_type' => Food::class,
]);
DB::table('journalables')->insert([
'journal_entry_id' => 5,
'journalable_id' => $foods['raisins']->id,
'journalable_type' => Food::class,
]);
}
}