Files
SkinbaseNova/app/Http/Controllers/Web/ArtworkPageController.php

140 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Http\Resources\ArtworkResource;
use App\Models\Artwork;
use App\Models\ArtworkComment;
use App\Services\ThumbnailPresenter;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
final class ArtworkPageController extends Controller
{
public function show(Request $request, int $id, ?string $slug = null): View|RedirectResponse
{
$artwork = Artwork::with(['user.profile', 'categories.contentType', 'tags', 'stats'])
->where('id', $id)
->public()
->published()
->firstOrFail();
$canonicalSlug = Str::slug((string) ($artwork->slug ?: $artwork->title));
if ($canonicalSlug === '') {
$canonicalSlug = (string) $artwork->id;
}
if ((string) $slug !== $canonicalSlug) {
return redirect()->route('art.show', [
'id' => $artwork->id,
'slug' => $canonicalSlug,
], 301);
}
$thumbMd = ThumbnailPresenter::present($artwork, 'md');
$thumbLg = ThumbnailPresenter::present($artwork, 'lg');
$thumbXl = ThumbnailPresenter::present($artwork, 'xl');
$thumbSq = ThumbnailPresenter::present($artwork, 'sq');
$artworkData = (new ArtworkResource($artwork))->toArray($request);
$canonical = route('art.show', ['id' => $artwork->id, 'slug' => $canonicalSlug]);
$authorName = $artwork->user?->name ?: $artwork->user?->username ?: 'Artist';
$description = Str::limit(trim(strip_tags((string) ($artwork->description ?? ''))), 160, '…');
$meta = [
'title' => sprintf('%s by %s | Skinbase', (string) $artwork->title, (string) $authorName),
'description' => $description !== '' ? $description : (string) $artwork->title,
'canonical' => $canonical,
'og_image' => $thumbXl['url'] ?? $thumbLg['url'] ?? null,
'og_width' => $thumbXl['width'] ?? $thumbLg['width'] ?? null,
'og_height' => $thumbXl['height'] ?? $thumbLg['height'] ?? null,
];
$categoryIds = $artwork->categories->pluck('id')->filter()->values();
$tagIds = $artwork->tags->pluck('id')->filter()->values();
$related = Artwork::query()
->with(['user', 'categories.contentType'])
->whereKeyNot($artwork->id)
->public()
->published()
->where(function ($query) use ($artwork, $categoryIds, $tagIds): void {
$query->where('user_id', $artwork->user_id);
if ($categoryIds->isNotEmpty()) {
$query->orWhereHas('categories', function ($categoryQuery) use ($categoryIds): void {
$categoryQuery->whereIn('categories.id', $categoryIds->all());
});
}
if ($tagIds->isNotEmpty()) {
$query->orWhereHas('tags', function ($tagQuery) use ($tagIds): void {
$tagQuery->whereIn('tags.id', $tagIds->all());
});
}
})
->latest('published_at')
->limit(12)
->get()
->map(function (Artwork $item): array {
$itemSlug = Str::slug((string) ($item->slug ?: $item->title));
if ($itemSlug === '') {
$itemSlug = (string) $item->id;
}
$md = ThumbnailPresenter::present($item, 'md');
$lg = ThumbnailPresenter::present($item, 'lg');
return [
'id' => (int) $item->id,
'title' => (string) $item->title,
'author' => (string) ($item->user?->name ?: $item->user?->username ?: 'Artist'),
'url' => route('art.show', ['id' => $item->id, 'slug' => $itemSlug]),
'thumb' => $md['url'] ?? null,
'thumb_srcset' => ($md['url'] ?? '') . ' 640w, ' . ($lg['url'] ?? '') . ' 1280w',
];
})
->values()
->all();
$comments = ArtworkComment::with(['user.profile'])
->where('artwork_id', $artwork->id)
->where('is_approved', true)
->orderBy('created_at')
->limit(500)
->get()
->map(fn(ArtworkComment $c) => [
'id' => $c->id,
'content' => (string) $c->content,
'created_at' => $c->created_at?->toIsoString(),
'user' => [
'id' => $c->user?->id,
'name' => $c->user?->name,
'username' => $c->user?->username,
'profile_url' => $c->user?->username ? '/@' . $c->user->username : null,
'avatar_url' => $c->user?->profile?->avatar_url,
],
])
->values()
->all();
return view('artworks.show', [
'artwork' => $artwork,
'artworkData' => $artworkData,
'presentMd' => $thumbMd,
'presentLg' => $thumbLg,
'presentXl' => $thumbXl,
'presentSq' => $thumbSq,
'meta' => $meta,
'relatedItems' => $related,
'comments' => $comments,
]);
}
}