Only Breeze's default auth/profile tests existed - nothing covered Workouts, Sessions, Exercises, Yoga, Favorites, Blog, or the Admin panel, which is the actual product. Adds factories for the domain models and 45 new feature tests covering the main flows plus authorization boundaries (owner-only access on workouts/sessions, admin-only access on /admin, drafts hidden from the public blog). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
87 lines
2.1 KiB
PHP
87 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class Exercise extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'name',
|
|
'slug',
|
|
'exercise_db_id',
|
|
'gif_url',
|
|
'poster_image',
|
|
'instructions',
|
|
];
|
|
|
|
// relations
|
|
public function targetMuscles()
|
|
{
|
|
return $this->belongsToMany(Muscle::class, 'exercise_target_muscle');
|
|
}
|
|
|
|
public function secondaryMuscles()
|
|
{
|
|
return $this->belongsToMany(Muscle::class, 'exercise_secondary_muscle');
|
|
}
|
|
|
|
public function bodyParts()
|
|
{
|
|
return $this->belongsToMany(BodyPart::class, 'body_part_exercise');
|
|
}
|
|
|
|
public function equipments()
|
|
{
|
|
return $this->belongsToMany(Equipment::class, 'equipment_exercise');
|
|
}
|
|
|
|
public function workoutExercises()
|
|
{
|
|
return $this->hasMany(WorkoutExercise::class);
|
|
}
|
|
|
|
public function favoritedBy()
|
|
{
|
|
return $this->belongsToMany(User::class, 'exercise_favorites')->withTimestamps();
|
|
}
|
|
|
|
public function aliases()
|
|
{
|
|
return $this->hasMany(ExerciseAlias::class);
|
|
}
|
|
|
|
public function getDisplayNameAttribute(): string
|
|
{
|
|
$name = (string) $this->attributes['name'] ?? '';
|
|
$userId = Auth::id();
|
|
if (!$userId) {
|
|
return $name;
|
|
}
|
|
// Use already loaded relation if present to avoid querying N+1
|
|
if ($this->relationLoaded('aliases')) {
|
|
$alias = $this->aliases->firstWhere('user_id', $userId);
|
|
return $alias?->name ?: $name;
|
|
}
|
|
$alias = $this->aliases()->where('user_id', $userId)->first();
|
|
return $alias?->name ?: $name;
|
|
}
|
|
|
|
public function getPosterUrlAttribute(): ?string
|
|
{
|
|
$poster = (string)($this->attributes['poster_image'] ?? '');
|
|
if ($poster === '') {
|
|
return null;
|
|
}
|
|
if (preg_match('/^https?:\/\//i', $poster)) {
|
|
return $poster;
|
|
}
|
|
return Storage::url($poster);
|
|
}
|
|
}
|