313 lines
12 KiB
PHP
313 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Web;
|
|
|
|
use App\Models\Category;
|
|
use App\Models\ContentType;
|
|
use App\Models\Artwork;
|
|
use App\Services\ArtworkService;
|
|
use App\Services\ArtworkSearchService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Pagination\AbstractPaginator;
|
|
use Illuminate\Pagination\AbstractCursorPaginator;
|
|
|
|
class BrowseGalleryController extends \App\Http\Controllers\Controller
|
|
{
|
|
private const CONTENT_TYPE_SLUGS = ['photography', 'wallpapers', 'skins', 'other'];
|
|
|
|
private const SORT_MAP = [
|
|
'latest' => 'created_at:desc',
|
|
'popular' => 'views:desc',
|
|
'liked' => 'likes:desc',
|
|
'downloads' => 'downloads:desc',
|
|
];
|
|
|
|
public function __construct(
|
|
private ArtworkService $artworks,
|
|
private ArtworkSearchService $search,
|
|
) {
|
|
}
|
|
|
|
public function browse(Request $request)
|
|
{
|
|
$sort = (string) $request->query('sort', 'latest');
|
|
$perPage = $this->resolvePerPage($request);
|
|
|
|
$artworks = Artwork::search('')->options([
|
|
'filter' => 'is_public = true AND is_approved = true',
|
|
'sort' => [self::SORT_MAP[$sort] ?? 'created_at:desc'],
|
|
])->paginate($perPage);
|
|
$seo = $this->buildPaginationSeo($request, url('/browse'), $artworks);
|
|
|
|
$mainCategories = $this->mainCategories();
|
|
|
|
return view('gallery.index', [
|
|
'gallery_type' => 'browse',
|
|
'mainCategories' => $mainCategories,
|
|
'subcategories' => $mainCategories,
|
|
'contentType' => null,
|
|
'category' => null,
|
|
'artworks' => $artworks,
|
|
'hero_title' => 'Browse Artworks',
|
|
'hero_description' => 'List of all uploaded artworks across Skins, Wallpapers, Photography, and Other.',
|
|
'breadcrumbs' => collect(),
|
|
'page_title' => 'Browse Uploaded Artworks - Photography, Wallpapers and Skins at SkinBase',
|
|
'page_meta_description' => "Browse Uploaded Photography, Wallpapers and Skins to one of the world's oldest online social community for artists and art enthusiasts.",
|
|
'page_meta_keywords' => 'photography, wallpapers, skins, stock, browse, social, community, artist, picture, photo',
|
|
'page_canonical' => $seo['canonical'],
|
|
'page_rel_prev' => $seo['prev'],
|
|
'page_rel_next' => $seo['next'],
|
|
'page_robots' => 'index,follow',
|
|
]);
|
|
}
|
|
|
|
public function content(Request $request, string $contentTypeSlug, ?string $path = null)
|
|
{
|
|
$contentSlug = strtolower($contentTypeSlug);
|
|
if (! in_array($contentSlug, self::CONTENT_TYPE_SLUGS, true)) {
|
|
abort(404);
|
|
}
|
|
|
|
$contentType = ContentType::where('slug', $contentSlug)->first();
|
|
if (! $contentType) {
|
|
abort(404);
|
|
}
|
|
|
|
$sort = (string) $request->query('sort', 'latest');
|
|
$perPage = $this->resolvePerPage($request);
|
|
|
|
$mainCategories = $this->mainCategories();
|
|
$rootCategories = $contentType->rootCategories()->orderBy('sort_order')->orderBy('name')->get();
|
|
|
|
$normalizedPath = trim((string) $path, '/');
|
|
if ($normalizedPath === '') {
|
|
$artworks = Artwork::search('')->options([
|
|
'filter' => 'is_public = true AND is_approved = true AND content_type = "' . $contentSlug . '"',
|
|
'sort' => [self::SORT_MAP[$sort] ?? 'created_at:desc'],
|
|
])->paginate($perPage);
|
|
$seo = $this->buildPaginationSeo($request, url('/' . $contentSlug), $artworks);
|
|
|
|
return view('gallery.index', [
|
|
'gallery_type' => 'content-type',
|
|
'mainCategories' => $mainCategories,
|
|
'subcategories' => $rootCategories,
|
|
'contentType' => $contentType,
|
|
'category' => null,
|
|
'artworks' => $artworks,
|
|
'hero_title' => $contentType->name,
|
|
'hero_description' => $contentType->description ?? ($contentType->name . ' artworks on Skinbase.'),
|
|
'breadcrumbs' => collect([(object) ['name' => $contentType->name, 'url' => '/' . $contentSlug]]),
|
|
'page_title' => $contentType->name,
|
|
'page_meta_description' => $contentType->description ?? ($contentType->name . ' artworks on Skinbase'),
|
|
'page_meta_keywords' => strtolower($contentType->slug) . ', skinbase, artworks, wallpapers, skins, photography',
|
|
'page_canonical' => $seo['canonical'],
|
|
'page_rel_prev' => $seo['prev'],
|
|
'page_rel_next' => $seo['next'],
|
|
'page_robots' => 'index,follow',
|
|
]);
|
|
}
|
|
|
|
$segments = array_values(array_filter(explode('/', $normalizedPath)));
|
|
$category = Category::findByPath($contentSlug, $segments);
|
|
if (! $category) {
|
|
abort(404);
|
|
}
|
|
|
|
$artworks = Artwork::search('')->options([
|
|
'filter' => 'is_public = true AND is_approved = true AND category = "' . $category->slug . '"',
|
|
'sort' => [self::SORT_MAP[$sort] ?? 'created_at:desc'],
|
|
])->paginate($perPage);
|
|
$seo = $this->buildPaginationSeo($request, url('/' . $contentSlug . '/' . strtolower($category->full_slug_path)), $artworks);
|
|
|
|
$subcategories = $category->children()->orderBy('sort_order')->orderBy('name')->get();
|
|
if ($subcategories->isEmpty()) {
|
|
$subcategories = $rootCategories;
|
|
}
|
|
|
|
$breadcrumbs = collect($category->breadcrumbs)
|
|
->map(function (Category $crumb) {
|
|
return (object) [
|
|
'name' => $crumb->name,
|
|
'url' => $crumb->url,
|
|
];
|
|
});
|
|
|
|
return view('gallery.index', [
|
|
'gallery_type' => 'category',
|
|
'mainCategories' => $mainCategories,
|
|
'subcategories' => $subcategories,
|
|
'contentType' => $contentType,
|
|
'category' => $category,
|
|
'artworks' => $artworks,
|
|
'hero_title' => $category->name,
|
|
'hero_description' => $category->description ?? ($contentType->name . ' artworks on Skinbase.'),
|
|
'breadcrumbs' => $breadcrumbs,
|
|
'page_title' => $category->name,
|
|
'page_meta_description' => $category->description ?? ($contentType->name . ' artworks on Skinbase'),
|
|
'page_meta_keywords' => strtolower($contentType->slug) . ', skinbase, artworks, wallpapers, skins, photography',
|
|
'page_canonical' => $seo['canonical'],
|
|
'page_rel_prev' => $seo['prev'],
|
|
'page_rel_next' => $seo['next'],
|
|
'page_robots' => 'index,follow',
|
|
]);
|
|
}
|
|
|
|
public function showArtwork(...$params)
|
|
{
|
|
$req = request();
|
|
$pathSegments = array_values(array_filter(explode('/', trim($req->path(), '/'))));
|
|
|
|
$contentTypeSlug = $params[0] ?? ($pathSegments[0] ?? null);
|
|
$categoryPath = $params[1] ?? null;
|
|
$artwork = $params[2] ?? null;
|
|
|
|
// If artwork wasn't provided (some route invocations supply fewer args),
|
|
// derive it from the request path's last segment.
|
|
if ($artwork === null) {
|
|
$artwork = end($pathSegments) ?: null;
|
|
}
|
|
|
|
$contentTypeSlug = strtolower((string) $contentTypeSlug);
|
|
$categoryPath = $categoryPath !== null ? trim((string) $categoryPath, '/') : (isset($pathSegments[1]) ? implode('/', array_slice($pathSegments, 1, max(0, count($pathSegments) - 2))) : '');
|
|
|
|
// Normalize artwork param if route-model binding returned an Artwork model
|
|
$artworkSlug = $artwork instanceof Artwork ? (string) $artwork->slug : (string) $artwork;
|
|
|
|
return app(\App\Http\Controllers\ArtworkController::class)->show(
|
|
$req,
|
|
$contentTypeSlug,
|
|
$categoryPath,
|
|
$artworkSlug
|
|
);
|
|
}
|
|
|
|
public function legacyCategory(Request $request, ?string $group = null, ?string $slug = null, ?string $id = null)
|
|
{
|
|
if ($id !== null && ctype_digit((string) $id)) {
|
|
$category = Category::with('contentType')->find((int) $id);
|
|
if (! $category || ! $category->contentType) {
|
|
abort(404);
|
|
}
|
|
|
|
return redirect($category->url, 301);
|
|
}
|
|
|
|
$contentSlug = strtolower((string) $group);
|
|
if (! in_array($contentSlug, self::CONTENT_TYPE_SLUGS, true)) {
|
|
abort(404);
|
|
}
|
|
|
|
$target = '/' . $contentSlug;
|
|
$normalizedSlug = trim((string) $slug, '/');
|
|
if ($normalizedSlug !== '') {
|
|
$target .= '/' . strtolower($normalizedSlug);
|
|
}
|
|
|
|
if ($request->query()) {
|
|
$target .= '?' . http_build_query($request->query());
|
|
}
|
|
|
|
return redirect($target, 301);
|
|
}
|
|
|
|
private function resolvePerPage(Request $request): int
|
|
{
|
|
$limit = (int) $request->query('limit', 0);
|
|
$perPage = (int) $request->query('per_page', 0);
|
|
|
|
$value = $limit > 0 ? $limit : ($perPage > 0 ? $perPage : 40);
|
|
|
|
return max(12, min($value, 80));
|
|
}
|
|
|
|
private function mainCategories(): Collection
|
|
{
|
|
return ContentType::orderBy('id')
|
|
->get(['name', 'slug'])
|
|
->map(function (ContentType $type) {
|
|
return (object) [
|
|
'id' => $type->id,
|
|
'name' => $type->name,
|
|
'slug' => $type->slug,
|
|
'url' => '/' . strtolower($type->slug),
|
|
];
|
|
});
|
|
}
|
|
|
|
private function buildPaginationSeo(Request $request, string $canonicalBaseUrl, mixed $paginator): array
|
|
{
|
|
$canonicalQuery = $request->query();
|
|
unset($canonicalQuery['grid']);
|
|
if (($canonicalQuery['page'] ?? null) !== null && (int) $canonicalQuery['page'] <= 1) {
|
|
unset($canonicalQuery['page']);
|
|
}
|
|
|
|
$canonical = $canonicalBaseUrl;
|
|
if ($canonicalQuery !== []) {
|
|
$canonical .= '?' . http_build_query($canonicalQuery);
|
|
}
|
|
|
|
$prev = null;
|
|
$next = null;
|
|
|
|
if ($paginator instanceof AbstractPaginator || $paginator instanceof AbstractCursorPaginator) {
|
|
$prev = $this->stripQueryParamFromUrl($paginator->previousPageUrl(), 'grid');
|
|
$next = $this->stripQueryParamFromUrl($paginator->nextPageUrl(), 'grid');
|
|
}
|
|
|
|
return [
|
|
'canonical' => $canonical,
|
|
'prev' => $prev,
|
|
'next' => $next,
|
|
];
|
|
}
|
|
|
|
private function stripQueryParamFromUrl(?string $url, string $queryParam): ?string
|
|
{
|
|
if ($url === null || $url === '') {
|
|
return null;
|
|
}
|
|
|
|
$parts = parse_url($url);
|
|
if (!is_array($parts)) {
|
|
return $url;
|
|
}
|
|
|
|
$query = [];
|
|
if (!empty($parts['query'])) {
|
|
parse_str($parts['query'], $query);
|
|
unset($query[$queryParam]);
|
|
}
|
|
|
|
$rebuilt = '';
|
|
if (isset($parts['scheme'])) {
|
|
$rebuilt .= $parts['scheme'] . '://';
|
|
}
|
|
if (isset($parts['user'])) {
|
|
$rebuilt .= $parts['user'];
|
|
if (isset($parts['pass'])) {
|
|
$rebuilt .= ':' . $parts['pass'];
|
|
}
|
|
$rebuilt .= '@';
|
|
}
|
|
if (isset($parts['host'])) {
|
|
$rebuilt .= $parts['host'];
|
|
}
|
|
if (isset($parts['port'])) {
|
|
$rebuilt .= ':' . $parts['port'];
|
|
}
|
|
$rebuilt .= $parts['path'] ?? '';
|
|
|
|
if ($query !== []) {
|
|
$rebuilt .= '?' . http_build_query($query);
|
|
}
|
|
|
|
if (isset($parts['fragment'])) {
|
|
$rebuilt .= '#' . $parts['fragment'];
|
|
}
|
|
|
|
return $rebuilt;
|
|
}
|
|
}
|