added yoga stuff, i18n, workout tracking and a dashboard to track progress
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\YogaCategory;
|
||||
use App\Models\YogaPose;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FetchYogaDataCommand extends Command
|
||||
{
|
||||
protected $signature = 'yoga:fetch {--force : Recreate slugs}';
|
||||
|
||||
protected $description = 'Fetch yoga categories and poses from public API and upsert into local DB';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$url = 'https://yoga-api-nzy4.onrender.com/v1/categories';
|
||||
$this->info('Fetching: ' . $url);
|
||||
|
||||
$response = Http::timeout(30)->acceptJson()->get($url);
|
||||
if (!$response->ok()) {
|
||||
$this->error('Failed to fetch data: ' . $response->status());
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$data = $response->json();
|
||||
if (!is_array($data)) {
|
||||
$this->error('Unexpected response format');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$countCategories = 0; $countPoses = 0;
|
||||
|
||||
foreach ($data as $cat) {
|
||||
$extId = (int) ($cat['id'] ?? 0);
|
||||
if ($extId <= 0) { continue; }
|
||||
|
||||
$category = YogaCategory::updateOrCreate(
|
||||
['external_id' => $extId],
|
||||
[
|
||||
'name' => (string) ($cat['category_name'] ?? 'Category ' . $extId),
|
||||
'description' => (string) ($cat['category_description'] ?? ''),
|
||||
]
|
||||
);
|
||||
$countCategories++;
|
||||
|
||||
$poses = $cat['poses'] ?? [];
|
||||
if (!is_array($poses)) { $poses = []; }
|
||||
|
||||
foreach ($poses as $pose) {
|
||||
$pExt = (int) ($pose['id'] ?? 0);
|
||||
if ($pExt <= 0) { continue; }
|
||||
|
||||
$payload = [
|
||||
'category_id' => $category->id,
|
||||
'english_name' => (string) ($pose['english_name'] ?? ''),
|
||||
'sanskrit_name_adapted' => (string) ($pose['sanskrit_name_adapted'] ?? ''),
|
||||
'sanskrit_name' => (string) ($pose['sanskrit_name'] ?? ''),
|
||||
'translation_name' => (string) ($pose['translation_name'] ?? ''),
|
||||
'description' => (string) ($pose['pose_description'] ?? ''),
|
||||
'benefits' => (string) ($pose['pose_benefits'] ?? ''),
|
||||
'url_svg' => (string) ($pose['url_svg'] ?? ''),
|
||||
'url_png' => (string) ($pose['url_png'] ?? ''),
|
||||
'url_svg_alt' => (string) ($pose['url_svg_alt'] ?? ''),
|
||||
];
|
||||
|
||||
$model = YogaPose::updateOrCreate(
|
||||
['external_id' => $pExt],
|
||||
$payload + [
|
||||
// slug may be regenerated with --force
|
||||
'slug' => $this->makeSlug($payload['english_name'], $pExt, $category->name),
|
||||
]
|
||||
);
|
||||
|
||||
if ($this->option('force')) {
|
||||
$model->slug = $this->makeSlug($payload['english_name'], $pExt, $category->name, true);
|
||||
$model->save();
|
||||
}
|
||||
|
||||
$countPoses++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("Imported {$countCategories} categories, {$countPoses} poses.");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
protected function makeSlug(string $englishName, int $externalId, string $categoryName = '', bool $force = false): string
|
||||
{
|
||||
$base = Str::slug($englishName !== '' ? $englishName : ('pose-' . $externalId));
|
||||
if ($base === '') { $base = 'pose-' . $externalId; }
|
||||
$slug = $base;
|
||||
$i = 1;
|
||||
while (YogaPose::where('slug', $slug)->exists()) {
|
||||
// If force-regenerating we allow different category-based suffix to reduce collisions
|
||||
$suffix = $force && $categoryName ? '-' . Str::slug($categoryName) : '';
|
||||
$slug = $base . $suffix . '-' . (++$i);
|
||||
}
|
||||
return $slug;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user