Update
This commit is contained in:
172
app/Services/MemeMediaService.php
Normal file
172
app/Services/MemeMediaService.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\MemeMedia;
|
||||
use Illuminate\Contracts\Pagination\CursorPaginator;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Collection as SupportCollection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class MemeMediaService
|
||||
{
|
||||
/**
|
||||
* Search memes with optional query and pagination
|
||||
*/
|
||||
public function searchMemes(?string $search = null, int $perPage = 24): CursorPaginator
|
||||
{
|
||||
$query = $this->buildSearchQuery($search);
|
||||
|
||||
return $query->cursorPaginate($perPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get popular keywords for filtering
|
||||
*/
|
||||
public function getPopularKeywords(int $limit = 20): SupportCollection
|
||||
{
|
||||
$cacheKey = "popular_keywords_limit_{$limit}";
|
||||
|
||||
return Cache::remember($cacheKey, 60 * 60 * 24, function () use ($limit) {
|
||||
return MemeMedia::where('is_enabled', true)
|
||||
->get()
|
||||
->pluck('keywords')
|
||||
->flatten()
|
||||
->countBy()
|
||||
->sort()
|
||||
->reverse()
|
||||
->take($limit)
|
||||
->keys();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available meme types for filtering
|
||||
*/
|
||||
public function getAvailableTypes(): SupportCollection
|
||||
{
|
||||
return MemeMedia::where('is_enabled', true)
|
||||
->distinct()
|
||||
->pluck('type')
|
||||
->filter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find meme by slug
|
||||
*/
|
||||
public function findBySlug(string $slug): MemeMedia
|
||||
{
|
||||
return MemeMedia::where('slug', $slug)
|
||||
->where('is_enabled', true)
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find meme by hashids
|
||||
*/
|
||||
public function findByHashIds(string $ids): MemeMedia
|
||||
{
|
||||
$memeId = hashids_decode($ids);
|
||||
|
||||
if (! $memeId) {
|
||||
throw new ModelNotFoundException('Meme not found');
|
||||
}
|
||||
|
||||
return MemeMedia::where('id', $memeId)
|
||||
->where('is_enabled', true)
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get related memes based on keywords
|
||||
*/
|
||||
public function getRelatedMemes(MemeMedia $meme, int $limit = 6): Collection
|
||||
{
|
||||
$relatedMemes = MemeMedia::where('is_enabled', true)
|
||||
->where('id', '!=', $meme->id)
|
||||
->where(function ($query) use ($meme) {
|
||||
if ($meme->keywords) {
|
||||
foreach ($meme->keywords as $keyword) {
|
||||
$query->orWhereJsonContains('keywords', $keyword)
|
||||
->orWhereJsonContains('action_keywords', $keyword)
|
||||
->orWhereJsonContains('emotion_keywords', $keyword)
|
||||
->orWhereJsonContains('misc_keywords', $keyword);
|
||||
}
|
||||
}
|
||||
})
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
// If we have less than the desired limit, fill up with random ones
|
||||
if ($relatedMemes->count() < $limit) {
|
||||
$excludeIds = $relatedMemes->pluck('id')->push($meme->id)->toArray();
|
||||
$needed = $limit - $relatedMemes->count();
|
||||
|
||||
$randomMemes = $this->fillWithRandomMemes($relatedMemes, $limit, $excludeIds);
|
||||
$relatedMemes = $relatedMemes->merge($randomMemes);
|
||||
}
|
||||
|
||||
return $relatedMemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill collection with random memes up to target count
|
||||
*/
|
||||
public function fillWithRandomMemes(Collection $existing, int $targetCount, array $excludeIds): Collection
|
||||
{
|
||||
$needed = $targetCount - $existing->count();
|
||||
|
||||
if ($needed <= 0) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return MemeMedia::where('is_enabled', true)
|
||||
->whereNotIn('id', $excludeIds)
|
||||
->inRandomOrder()
|
||||
->limit($needed)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build search query with keyword matching
|
||||
*/
|
||||
private function buildSearchQuery(?string $search = null): Builder
|
||||
{
|
||||
$query = $this->getEnabledMemesQuery();
|
||||
|
||||
if ($search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'ilike', "%{$search}%")
|
||||
->orWhere('description', 'ilike', "%{$search}%")
|
||||
->orWhereJsonContains('keywords', $search)
|
||||
->orWhereJsonContains('action_keywords', $search)
|
||||
->orWhereJsonContains('emotion_keywords', $search)
|
||||
->orWhereJsonContains('misc_keywords', $search);
|
||||
});
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enabled memes for sitemap generation
|
||||
*/
|
||||
public function getAllEnabledMemes(): Collection
|
||||
{
|
||||
return MemeMedia::where('is_enabled', true)
|
||||
->orderBy('updated_at', 'desc')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base query for enabled memes
|
||||
*/
|
||||
private function getEnabledMemesQuery(): Builder
|
||||
{
|
||||
return MemeMedia::query()
|
||||
->where('is_enabled', true)
|
||||
->orderBy('id', 'desc');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user