From dc4d7987e8380d6404c8e8d52d83e12405fb6cc6 Mon Sep 17 00:00:00 2001 From: "Christopher C. Wells" Date: Sat, 15 May 2021 08:59:53 -0700 Subject: [PATCH] Create JournalDate model for setting per-date goals --- app/Models/JournalDate.php | 62 +++++++++++++++++++ app/Models/User.php | 35 ++++++++++- database/Factories/GoalFactory.php | 19 +++--- database/Factories/JournalDateFactory.php | 29 +++++++++ ...5_15_082223_create_journal_dates_table.php | 37 +++++++++++ 5 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 app/Models/JournalDate.php create mode 100644 database/Factories/JournalDateFactory.php create mode 100644 database/migrations/2021_05_15_082223_create_journal_dates_table.php diff --git a/app/Models/JournalDate.php b/app/Models/JournalDate.php new file mode 100644 index 0000000..1013383 --- /dev/null +++ b/app/Models/JournalDate.php @@ -0,0 +1,62 @@ + 'datetime:Y-m-d', + ]; + + /** + * Get the Goal for this date. + */ + public function goal(): BelongsTo { + return $this->belongsTo(Goal::class); + } + + /** + * Get the User this journal date belongs to. + */ + public function user(): BelongsTo { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index bf9f51a..daeadc5 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Carbon; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; @@ -50,6 +49,8 @@ use Spatie\MediaLibrary\MediaCollections\Models\Media; * @method static \Illuminate\Database\Eloquent\Builder|User whereSlug($value) * @method static \Illuminate\Database\Eloquent\Builder|User withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug) * @mixin \Eloquent + * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\JournalDate[] $journalDates + * @property-read int|null $journal_dates_count */ final class User extends Authenticatable implements HasMedia { @@ -98,6 +99,13 @@ final class User extends Authenticatable implements HasMedia return $this->hasMany(Goal::class); } + /** + * Get the User's journal dates. + */ + public function journalDates(): HasMany { + return $this->hasMany(JournalDate::class); + } + /** * Get the User's journal entries. */ @@ -107,13 +115,36 @@ final class User extends Authenticatable implements HasMedia /** * Get user's goal (if one exists) for a specific date. + * + * The primary use for a JournalDate entry right now is the goal so this + * method also creates a JournalDate if one does not already exist. */ public function getGoalByDate(Carbon $date): ?Goal { + /** @var \App\Models\JournalDate $journal_date */ + $journal_date = $this->journalDates()->whereDate('date', '=', $date)->first(); + if (empty($journal_date)) { + $journal_date = JournalDate::make(['date' => $date])->user()->associate(Auth::user()); + } + if ($journal_date->goal) { + return $journal_date->goal; + } + + // Check for a goal based on day of week configurations. $day = Goal::days()->firstWhere('dow', $date->format('N')); if (!$day) { throw new \BadMethodCallException("No day with `dow` value {$date->format('N')}."); } - return $this->goals()->whereRaw("(days & {$day['value']}) != 0")->get()->first(); + /** @var \App\Models\Goal $goal */ + $goal = $this->goals()->whereRaw("(days & {$day['value']}) != 0")->first(); + if (!empty($goal)) { + $journal_date->goal()->associate($goal); + } + + if ($journal_date->hasChanges(['date', 'goal'])) { + $journal_date->save(); + } + + return $goal; } /** diff --git a/database/Factories/GoalFactory.php b/database/Factories/GoalFactory.php index 2878c7b..434d713 100644 --- a/database/Factories/GoalFactory.php +++ b/database/Factories/GoalFactory.php @@ -3,6 +3,7 @@ namespace Database\Factories; use App\Models\Goal; +use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; class GoalFactory extends Factory @@ -15,16 +16,18 @@ class GoalFactory extends Factory /** * {@inheritdoc} */ - public function definition() + public function definition(): array { - $from = $this->faker->dateTimeThisMonth; - $to = $this->faker->dateTimeBetween($from, '+1 year'); return [ - 'from' => $this->faker->randomElement([$from, null]), - 'to' => $this->faker->randomElement([$to, null]), - 'frequency' => $this->faker->randomElement(Goal::$frequencyOptions)['value'], - 'name' => $this->faker->randomElement(Goal::getNameOptions())['value'], - 'goal' => $this->faker->numberBetween(0, 2000), + 'user_id' => User::factory(), + 'name' => $this->faker->words, + 'days' => $this->faker->randomElement(Goal::days()->pluck('value')->all()), + 'calories' => $this->faker->numberBetween(1600, 2500), + 'fat' => $this->faker->numberBetween(40, 90), + 'cholesterol' => $this->faker->numberBetween(0, 500), + 'sodium' => $this->faker->numberBetween(0, 3000), + 'carbohydrates' => $this->faker->numberBetween(50, 100), + 'protein' => $this->faker->numberBetween(90, 200), ]; } } diff --git a/database/Factories/JournalDateFactory.php b/database/Factories/JournalDateFactory.php new file mode 100644 index 0000000..d2c8211 --- /dev/null +++ b/database/Factories/JournalDateFactory.php @@ -0,0 +1,29 @@ + $this->faker->dateTimeThisMonth, + 'user_id' => User::factory(), + 'goal_id' => Goal::factory(), + ]; + } + +} diff --git a/database/migrations/2021_05_15_082223_create_journal_dates_table.php b/database/migrations/2021_05_15_082223_create_journal_dates_table.php new file mode 100644 index 0000000..35d96ce --- /dev/null +++ b/database/migrations/2021_05_15_082223_create_journal_dates_table.php @@ -0,0 +1,37 @@ +id(); + $table->date('date')->useCurrent(); + $table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete(); + $table->foreignIdFor(Goal::class)->nullable()->constrained()->cascadeOnUpdate()->cascadeOnDelete(); + $table->timestamps(); + $table->unique(['date', 'user_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('journal_dates'); + } +}