Skip to main content

Overview

The ActivityExercise model tracks physical activities and exercise sessions for users in Health Manager. It supports detailed exercise logging with duration tracking, descriptions, and file attachments through polymorphic relationships.

Namespace

App\Models\ActivityExercise

Class Declaration

class ActivityExercise extends Model

Database Schema

The activity_exercises table includes the following columns:
id
bigint
required
Primary key, auto-incrementing
user_id
bigint
required
Foreign key referencing users table (cascades on delete)
title
string
required
Exercise or activity title
date
datetime
required
Date and time when the activity was performed
description
text
Optional detailed description of the activity
duration_minutes
integer
Duration of the activity in minutes
file_path
string
Legacy file path (deprecated - use attachments relationship instead)
created_at
timestamp
Record creation timestamp
updated_at
timestamp
Record last update timestamp

Fillable Attributes

These attributes can be mass assigned:
user_id
integer
required
ID of the user who performed this activity
title
string
required
Activity title (e.g., “Morning Run”, “Gym Workout”, “Yoga Session”)
date
datetime
required
Date and time of the activity in Y-m-d H:i:s format
description
string
Detailed description, notes, or workout details
duration_minutes
integer
Duration in minutes (e.g., 30, 45, 60)
file_path
string
Legacy field for single file attachment (use attachments relationship for multiple files)

Casts

[
    'date' => 'datetime',
]
The date attribute is automatically cast to a Carbon datetime instance.

Relationships

user()

Belongs to relationship with the User model.
public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}
Example Usage:
$activity = ActivityExercise::find(1);
$userName = $activity->user->name;

attachments()

Polymorphic relationship for file attachments (e.g., workout photos, GPS tracks, screenshots).
public function attachments(): MorphMany
{
    return $this->morphMany(Attachment::class, 'model');
}
Example Usage:
$activity = ActivityExercise::find(1);

// Get all attachments
$files = $activity->attachments;

// Add new attachment
$activity->attachments()->create([
    'file_path' => 'activities/workout-photo.jpg',
    'file_name' => 'workout-photo.jpg',
]);

Usage Examples

Creating Exercise Activities

use App\Models\ActivityExercise;
use Carbon\Carbon;

// Create a simple activity
$activity = ActivityExercise::create([
    'user_id' => auth()->id(),
    'title' => 'Morning Run',
    'date' => now(),
    'duration_minutes' => 30,
    'description' => '5K run in the park',
]);

echo "Activity logged: {$activity->title} - {$activity->duration_minutes} minutes";

Creating Activity with Attachments

$activity = ActivityExercise::create([
    'user_id' => auth()->id(),
    'title' => 'HIIT Workout',
    'date' => Carbon::parse('2026-03-05 18:00:00'),
    'duration_minutes' => 45,
    'description' => '4 rounds: burpees, squats, push-ups, mountain climbers',
]);

// Add workout photos
$activity->attachments()->createMany([
    [
        'file_path' => 'storage/activities/before-workout.jpg',
        'file_name' => 'Before Workout.jpg',
    ],
    [
        'file_path' => 'storage/activities/after-workout.jpg',
        'file_name' => 'After Workout.jpg',
    ],
]);

Querying Activities

// Get all activities for current user
$allActivities = ActivityExercise::where('user_id', auth()->id())
    ->orderBy('date', 'desc')
    ->get();

// Get recent activities
$recent = ActivityExercise::where('user_id', auth()->id())
    ->where('date', '>=', now()->subDays(7))
    ->orderBy('date', 'desc')
    ->get();

// Get activities with attachments
$withFiles = ActivityExercise::with('attachments')
    ->where('user_id', auth()->id())
    ->get();

// Get activities for specific date range
$marchActivities = ActivityExercise::where('user_id', auth()->id())
    ->whereBetween('date', [
        Carbon::parse('2026-03-01'),
        Carbon::parse('2026-03-31')
    ])
    ->orderBy('date', 'asc')
    ->get();

Calculating Activity Statistics

// Total exercise time this month
$totalMinutes = ActivityExercise::where('user_id', auth()->id())
    ->whereMonth('date', now()->month)
    ->sum('duration_minutes');

echo "Total exercise time: {$totalMinutes} minutes (" . round($totalMinutes / 60, 1) . " hours)";

// Average duration
$avgDuration = ActivityExercise::where('user_id', auth()->id())
    ->avg('duration_minutes');

echo "Average workout duration: " . round($avgDuration) . " minutes";

// Activity count by period
$thisWeek = ActivityExercise::where('user_id', auth()->id())
    ->whereBetween('date', [now()->startOfWeek(), now()->endOfWeek()])
    ->count();

$thisMonth = ActivityExercise::where('user_id', auth()->id())
    ->whereMonth('date', now()->month)
    ->count();

echo "Activities: {$thisWeek} this week, {$thisMonth} this month";

Filtering by Activity Type

// Find running activities
$runs = ActivityExercise::where('user_id', auth()->id())
    ->where('title', 'like', '%run%')
    ->orderBy('date', 'desc')
    ->get();

// Find gym workouts
$gymWorkouts = ActivityExercise::where('user_id', auth()->id())
    ->where('title', 'like', '%gym%')
    ->orWhere('title', 'like', '%workout%')
    ->orderBy('date', 'desc')
    ->get();

// Find activities by minimum duration
$longWorkouts = ActivityExercise::where('user_id', auth()->id())
    ->where('duration_minutes', '>=', 60)
    ->orderBy('duration_minutes', 'desc')
    ->get();

Updating Activities

$activity = ActivityExercise::find(1);

$activity->update([
    'title' => 'Evening Run - Updated',
    'duration_minutes' => 35,
    'description' => 'Extended the route by 1K',
]);

Filtering by Date

use Carbon\Carbon;

// Today's activities
$today = ActivityExercise::whereDate('date', today())
    ->where('user_id', auth()->id())
    ->get();

// This week's activities
$thisWeek = ActivityExercise::whereBetween('date', [
        now()->startOfWeek(),
        now()->endOfWeek()
    ])
    ->where('user_id', auth()->id())
    ->get();

// Last 30 days
$last30Days = ActivityExercise::where('user_id', auth()->id())
    ->where('date', '>=', now()->subDays(30))
    ->orderBy('date', 'desc')
    ->get();

Activity Streaks

// Calculate current streak
function calculateStreak($userId)
{
    $activities = ActivityExercise::where('user_id', $userId)
        ->whereDate('date', '>=', now()->subDays(90))
        ->orderBy('date', 'desc')
        ->get()
        ->groupBy(function ($activity) {
            return $activity->date->format('Y-m-d');
        });

    $streak = 0;
    $currentDate = now();

    while ($activities->has($currentDate->format('Y-m-d'))) {
        $streak++;
        $currentDate->subDay();
    }

    return $streak;
}

$streak = calculateStreak(auth()->id());
echo "Current streak: {$streak} days";

Working with Relationships

// Eager load relationships
$activities = ActivityExercise::with(['user', 'attachments'])
    ->where('date', '>=', now()->subDays(7))
    ->get();

foreach ($activities as $activity) {
    echo "{$activity->user->name}: {$activity->title} - {$activity->duration_minutes} min\n";
    echo "Attachments: {$activity->attachments->count()}\n";
}

Charting Activity Data

// Get weekly activity data for chart
$weeklyData = [];

for ($i = 6; $i >= 0; $i--) {
    $date = now()->subDays($i);
    $totalMinutes = ActivityExercise::where('user_id', auth()->id())
        ->whereDate('date', $date)
        ->sum('duration_minutes');

    $weeklyData[] = [
        'date' => $date->format('Y-m-d'),
        'day' => $date->format('l'),
        'minutes' => $totalMinutes,
    ];
}

return response()->json($weeklyData);

Deleting Activities

$activity = ActivityExercise::find(1);

// Delete activity with attachments
$activity->attachments()->delete();
$activity->delete();

// Delete old activities (e.g., older than 2 years)
ActivityExercise::where('user_id', auth()->id())
    ->where('date', '<', now()->subYears(2))
    ->delete();

JSON Serialization Example

$activity = ActivityExercise::with(['user', 'attachments'])->find(1);

return response()->json($activity);
Output:
{
  "id": 1,
  "user_id": 5,
  "title": "Morning Run",
  "date": "2026-03-05T07:00:00.000000Z",
  "description": "5K run in the park",
  "duration_minutes": 30,
  "file_path": null,
  "created_at": "2026-03-05T07:30:00.000000Z",
  "updated_at": "2026-03-05T07:30:00.000000Z",
  "user": {
    "id": 5,
    "name": "John Doe",
    "email": "[email protected]",
    "username": "johndoe"
  },
  "attachments": [
    {
      "id": 1,
      "model_type": "App\\Models\\ActivityExercise",
      "model_id": 1,
      "file_path": "storage/activities/workout-photo.jpg",
      "file_name": "Workout Photo.jpg",
      "created_at": "2026-03-05T07:31:00.000000Z",
      "updated_at": "2026-03-05T07:31:00.000000Z"
    }
  ]
}

API Response Example for Activity Dashboard

// Controller method to get activity summary
public function getActivitySummary()
{
    $userId = auth()->id();
    
    $thisWeek = ActivityExercise::where('user_id', $userId)
        ->whereBetween('date', [now()->startOfWeek(), now()->endOfWeek()])
        ->get();

    $thisMonth = ActivityExercise::where('user_id', $userId)
        ->whereMonth('date', now()->month)
        ->get();

    return response()->json([
        'this_week' => [
            'count' => $thisWeek->count(),
            'total_minutes' => $thisWeek->sum('duration_minutes'),
        ],
        'this_month' => [
            'count' => $thisMonth->count(),
            'total_minutes' => $thisMonth->sum('duration_minutes'),
        ],
        'recent_activities' => ActivityExercise::where('user_id', $userId)
            ->orderBy('date', 'desc')
            ->limit(5)
            ->get(),
    ]);
}
Response:
{
  "this_week": {
    "count": 4,
    "total_minutes": 180
  },
  "this_month": {
    "count": 12,
    "total_minutes": 540
  },
  "recent_activities": [
    {
      "id": 1,
      "user_id": 5,
      "title": "Morning Run",
      "date": "2026-03-05T07:00:00.000000Z",
      "duration_minutes": 30
    },
    {
      "id": 2,
      "user_id": 5,
      "title": "Gym Workout",
      "date": "2026-03-04T18:00:00.000000Z",
      "duration_minutes": 60
    }
  ]
}

Traits Used

  • HasFactory - Enables model factories for testing and seeding

Build docs developers (and LLMs) love