Files
fitness/app/Console/Commands/FetchExerciseDbDataCommand.php
T
2025-10-02 22:52:13 +03:00

188 lines
5.6 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\BodyPart;
use App\Models\Equipment;
use App\Models\Exercise;
use App\Models\Muscle;
use App\Services\ExerciseDb\ApiService;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class FetchExerciseDbDataCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'fetch:exercise';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fetch all exercises from ExerciseDB API and store them locally.';
private ApiService $apiService;
public function __construct(ApiService $apiService)
{
$this->apiService = $apiService;
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle(): int
{
$page = 1;
$stored = 0;
$updated = 0;
$this->info('Fetching exercises from ExerciseDB...');
while (true) {
$results = $this->apiService->fetch($page);
$results = $results['data'];
$count = count($results);
if ($count === 0) {
break;
}
[$s, $u] = $this->process($results);
$stored += $s;
$updated += $u;
$this->info("Processed page {$page} with {$count} items.");
if ($count < ApiService::PER_PAGE) {
break;
}
$page++;
sleep(5);
}
$this->info("Done. Created {$stored}, updated {$updated} exercises.");
return self::SUCCESS;
}
/**
* @param array<int, array<string, mixed>> $results
* @return array{int,int} [created, updated]
*/
private function process(array $results): array
{
$created = 0;
$updated = 0;
foreach ($results as $item) {
$exerciseDbId = (string)($item['exerciseId'] ?? '');
if ($exerciseDbId === '') {
continue;
}
$name = (string)($item['name'] ?? '');
$gifUrl = (string)($item['gifUrl'] ?? '');
$instructions = $item['instructions'] ?? [];
if (is_array($instructions)) {
$instructionsText = implode("\n", array_filter(array_map('strval', $instructions)));
} else {
$instructionsText = (string)$instructions;
}
$slug = Str::slug($name) ?: $exerciseDbId;
$values = [
'name' => $name,
'slug' => $slug,
'gif_url' => $gifUrl,
'instructions' => $instructionsText,
];
$existing = Exercise::where('exercise_db_id', $exerciseDbId)->first();
$exercise = Exercise::updateOrCreate(
['exercise_db_id' => $exerciseDbId],
$values,
);
if ($existing) { $updated++; } else { $created++; }
// Relations
// Body part (string)
$bodyPartVal = $item['bodyPart'] ?? null;
$bodyPartIds = [];
if ($bodyPartVal) {
$bodyParts = is_array($bodyPartVal) ? $bodyPartVal : [$bodyPartVal];
foreach ($bodyParts as $bp) {
$bpName = (string)$bp;
$bpSlug = Str::slug($bpName);
$bpModel = BodyPart::firstOrCreate(['slug' => $bpSlug], ['name' => $bpName]);
$bodyPartIds[] = $bpModel->id;
}
}
if ($bodyPartIds) {
$exercise->bodyParts()->sync($bodyPartIds);
}
// Target muscle (string)
$targetVal = $item['target'] ?? null;
$targetIds = [];
if ($targetVal) {
$targets = is_array($targetVal) ? $targetVal : [$targetVal];
foreach ($targets as $tm) {
$mName = (string)$tm;
$mSlug = Str::slug($mName);
$mModel = Muscle::firstOrCreate(['slug' => $mSlug], ['name' => $mName]);
$targetIds[] = $mModel->id;
}
}
if ($targetIds) {
$exercise->targetMuscles()->sync($targetIds);
}
// Secondary muscles (array)
$secVal = $item['secondaryMuscles'] ?? [];
$secondaryIds = [];
if (!is_array($secVal)) { $secVal = [$secVal]; }
foreach ($secVal as $sm) {
$smName = (string)$sm;
if ($smName === '') { continue; }
$smSlug = Str::slug($smName);
$mModel = Muscle::firstOrCreate(['slug' => $smSlug], ['name' => $smName]);
$secondaryIds[] = $mModel->id;
}
if ($secondaryIds) {
$exercise->secondaryMuscles()->sync($secondaryIds);
}
// Equipment (string or array depending on source variant)
$equipVal = $item['equipment'] ?? null;
$equipmentIds = [];
if ($equipVal) {
$equipments = is_array($equipVal) ? $equipVal : [$equipVal];
foreach ($equipments as $eq) {
$eqName = (string)$eq;
$eqSlug = Str::slug($eqName);
$eqModel = Equipment::firstOrCreate(['slug' => $eqSlug], ['name' => $eqName]);
$equipmentIds[] = $eqModel->id;
}
}
if ($equipmentIds) {
$exercise->equipments()->sync($equipmentIds);
}
}
return [$created, $updated];
}
}