mirror of https://github.com/kcal-app/kcal.git
Create JournalDate model for setting per-date goals
This commit is contained in:
parent
91fd85ef83
commit
dc4d7987e8
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App\Models\JournalDate
|
||||||
|
*
|
||||||
|
* @property int $id
|
||||||
|
* @property \datetime $date
|
||||||
|
* @property int $user_id
|
||||||
|
* @property int|null $goal_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Goal|null $goal
|
||||||
|
* @property-read \App\Models\User $user
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereDate($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereGoalId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereUserId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
final class JournalDate extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'date',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'date' => '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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
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 whereSlug($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|User withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
|
* @method static \Illuminate\Database\Eloquent\Builder|User withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
|
||||||
* @mixin \Eloquent
|
* @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
|
final class User extends Authenticatable implements HasMedia
|
||||||
{
|
{
|
||||||
|
|
@ -98,6 +99,13 @@ final class User extends Authenticatable implements HasMedia
|
||||||
return $this->hasMany(Goal::class);
|
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.
|
* 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.
|
* 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 {
|
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'));
|
$day = Goal::days()->firstWhere('dow', $date->format('N'));
|
||||||
if (!$day) {
|
if (!$day) {
|
||||||
throw new \BadMethodCallException("No day with `dow` value {$date->format('N')}.");
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
use App\Models\Goal;
|
use App\Models\Goal;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
class GoalFactory extends Factory
|
class GoalFactory extends Factory
|
||||||
|
|
@ -15,16 +16,18 @@ class GoalFactory extends Factory
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function definition()
|
public function definition(): array
|
||||||
{
|
{
|
||||||
$from = $this->faker->dateTimeThisMonth;
|
|
||||||
$to = $this->faker->dateTimeBetween($from, '+1 year');
|
|
||||||
return [
|
return [
|
||||||
'from' => $this->faker->randomElement([$from, null]),
|
'user_id' => User::factory(),
|
||||||
'to' => $this->faker->randomElement([$to, null]),
|
'name' => $this->faker->words,
|
||||||
'frequency' => $this->faker->randomElement(Goal::$frequencyOptions)['value'],
|
'days' => $this->faker->randomElement(Goal::days()->pluck('value')->all()),
|
||||||
'name' => $this->faker->randomElement(Goal::getNameOptions())['value'],
|
'calories' => $this->faker->numberBetween(1600, 2500),
|
||||||
'goal' => $this->faker->numberBetween(0, 2000),
|
'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),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Goal;
|
||||||
|
use App\Models\JournalDate;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class JournalDateFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $model = JournalDate::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'date' => $this->faker->dateTimeThisMonth,
|
||||||
|
'user_id' => User::factory(),
|
||||||
|
'goal_id' => Goal::factory(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Goal;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateJournalDatesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('journal_dates', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue