query('q', '')); $category = (int) $request->query('category', 0); $benefit = trim((string) $request->query('benefit', '')); $perPage = (int) $request->query('per_page', 12); if ($perPage < 6 || $perPage > 60) { $perPage = 12; } $query = YogaPose::query()->with('category') ->when($q !== '', function ($qb) use ($q) { $qb->where(function ($sub) use ($q) { $sub->where('english_name', 'like', "%{$q}%") ->orWhere('sanskrit_name', 'like', "%{$q}%") ->orWhere('sanskrit_name_adapted', 'like', "%{$q}%"); }); }) ->when($category > 0, function ($qb) use ($category) { $qb->where('category_id', $category); }) ->when($benefit !== '', function ($qb) use ($benefit) { $qb->where('benefits', 'like', "%{$benefit}%"); }) ->orderBy('english_name'); $poses = $query->paginate($perPage)->withQueryString(); $categories = YogaCategory::orderBy('name')->get(['id','name']); return view('yoga.index', [ 'poses' => $poses, 'filters' => [ 'q' => $q, 'category' => $category, 'benefit' => $benefit, 'per_page' => $perPage, ], 'categories' => $categories, ]); } public function show(YogaPose $pose): View { $pose->load('category'); // Find similar poses by same category or overlapping benefits keywords $benefits = (string) $pose->benefits; $tokens = collect(preg_split('/[^\p{L}]+/u', mb_strtolower($benefits))) ->filter(fn($t) => $t !== null && $t !== '' && mb_strlen($t) >= 4) ->unique() ->take(8) ->values() ->all(); $similarQuery = YogaPose::query() ->with('category') ->where('id', '!=', $pose->id) ->where(function ($q) use ($pose, $tokens) { // Same category if ($pose->category_id) { $q->orWhere('category_id', $pose->category_id); } // Overlapping benefits terms foreach ($tokens as $tk) { $q->orWhere('benefits', 'like', "%{$tk}%"); } }) ->orderBy('english_name') ->limit(9); $similarPoses = $similarQuery->get(); return view('yoga.show', compact('pose', 'similarPoses')); } }