ldc-groupe/app/Http/Controllers/Front/PostsController.php

290 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers\Front;
use App\Models\News;
use App\Models\NewsTag;
use App\Enums\YearsEnum;
use App\Models\Document;
use App\Enums\OrdersEnum;
use App\Models\DocumentTag;
use Illuminate\Support\Str;
use App\Helpers\CollectionHelper;
use App\Enums\News\NewsStatusEnum;
use Illuminate\Support\Facades\App;
use App\Helpers\BladeComponentHelper;
use Illuminate\Support\Facades\Cache;
use App\Http\Requests\Front\PostsRequest;
use Illuminate\Database\Eloquent\Builder;
use App\Enums\Document\DocumentStatusEnum;
use Illuminate\Database\Eloquent\Collection;
use Uwil\LaravelCommon\Controllers\Controller;
class PostsController extends Controller
{
/**
* Build the common filters configuration for front-end listing pages
*
* If the type is "documents" the "order" filter is included
*
* @param string $type
* @param string $category
* @param \Illuminate\Database\Eloquent\Collection $publishedTags
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return array
*/
private function getFilters(string $type, string $category, Collection $publishedTags, Builder $query): array
{
$filters = [];
$collectionHelper = new CollectionHelper();
$tags = collect($publishedTags)
->map(fn($tag) => [
'title' => $tag->name,
'tag' => $tag->slug,
'category' => $category,
])
->values();
$enumYears = collect(YearsEnum::toArray())
->map(fn($year) => YearsEnum::make((int) $year->value))
->map(fn($year) => [
'title' => trans($year->label()),
'tag' => Str::replace('/', '-', $year->label()),
'value' => $type === "news" ? explode('/', $year->label())[1] : $year->value,
'category' => $category,
])
->sortDesc()
->values();
$orders = collect(OrdersEnum::toArray())
->map(fn($order) => OrdersEnum::make((int) $order->value))
->filter(fn($orderLocal) => $orderLocal->ordersWithLocal())
->map(fn($orderLocal) => [
'title' => ucfirst(trans($orderLocal->label())),
'tag' => Str::slug($orderLocal->name),
'category' => $category,
])
->values();
/** Sort displayed years */
$years = $collectionHelper->getMatchingValues(
$collectionHelper->getUniqueYearsFromQuery($query, 'published_at'),
$enumYears,
'value'
);
if ($type === "documents") {
$filters[] = [
'title' => ucfirst(__('front.news.order')),
'name' => 'order',
'fields' => $orders,
];
}
$filters[] = [
'title' => $type === "documents" ? ucfirst(__('front.news.document')) : ucfirst(__('front.news.theme')),
'name' => 'tags',
'fields' => $tags,
];
$filters[] = [
'title' => $type === "documents" ? ucfirst(__('front.news.exercise')) : ucfirst(__('front.news.year')),
'name' => 'years',
'fields' => $years,
];
return $filters;
}
/**
* Returns news in JSON format filtered by category and language
* Optionally, the results can be further filtered by tags, and years
*
* @param \App\Http\Requests\Front\PostsRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function ajaxLoadNews(PostsRequest $request): \Illuminate\Http\JsonResponse
{
$data = $request->validated();
$perPage = 9;
$selectedFilters = [];
$category = $data['category'];
app()->setLocale($data['locale']);
$locale = app()->getLocale();
$publishedNewsTags = NewsTag::getTagsByCategoryInCurrentLocale($category);
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\News> $query */
$query = News::getPublishedNewsByCategoryInCurrentLocale($category);
$requestedTags = collect($data['filters']['tags'] ?? '')
->filter()
->unique()
->values();
$selectedTags = $publishedNewsTags->filter(fn ($tag) => $requestedTags->contains($tag->slug ?? null))
->map(fn ($tag) => [
'id' => $tag->id,
'title' => $tag->name,
'tag' => $tag->slug,
'color' => $tag->color,
'category' => $category,
])
->values();
if ($selectedTags->isNotEmpty()) {
$query->whereHas('tags', function ($q) use ($selectedTags) {
$q->whereIn('newsable_id', $selectedTags->map->id->all());
});
$selectedFilters['tags'] = $selectedTags;
}
$selectedYears = collect($data['filters']['years'] ?? '')
->map(fn (string $label) => YearsEnum::makeFromLabel(Str::replace('-', '/', $label)))
->filter()
->map(fn($year) => [
'title' => $year->label(),
'tag' => Str::replace('/', '-', $year->label()),
'value' => explode('/', $year->label())[1],
'category' => $category,
])
->values();
if ($selectedYears->isNotEmpty()) {
foreach ($selectedYears->map->value->all() as $value) {
$query->whereYear('published_at', $value);
}
$selectedFilters['years'] = $selectedYears;
}
/** Sort columns with a query */
$this->sortQuery($query);
$filters = $this->getFilters('news', $category, $publishedNewsTags, $query);
/** Custom pagination */
$newsModel = $query->paginate($perPage, ['*'], 'page', $data['page'] ?? 1);
return response()->json([
'pagination' => [
'total' => $newsModel->total(),
'nbItems' => count($newsModel->items()),
'currentPage' => $newsModel->currentPage(),
'lastPage' => $newsModel->lastPage(),
'hasMore' => $newsModel->currentPage() < $newsModel->lastPage(),
],
'filters' => view('components.front.posts.filters-dropdowns', ['filters' => $filters])->render(),
'selectedFilters' => view('components.front.posts.selected-filters', ['selectedFilters' => $selectedFilters])->render(),
'news' => view('components.front.posts.news', ['newsList' => $newsModel->items()])->render()
]);
}
/**
* Returns documents in JSON format filtered by category and language
* Optionally, the results can be further filtered by order, tags, and years
*
* @param \App\Http\Requests\Front\PostsRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function ajaxLoadDocuments(PostsRequest $request): \Illuminate\Http\JsonResponse
{
$data = $request->validated();
$perPage = 3;
$selectedFilters = [];
$category = $data['category'];
app()->setLocale($data['locale']);
$locale = app()->getLocale();
$publishedDocumentsTags = DocumentTag::getTagsByCategoryInCurrentLocale($category);
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Document> $query */
$query = Document::getPublishedDocumentsByCategoryInCurrentLocale($category);
$requestedTags = collect($data['filters']['tags'] ?? '')
->filter()
->unique()
->values();
$selectedTags = $publishedDocumentsTags->filter(fn ($tag) => $requestedTags->contains($tag->slug ?? null))
->map(fn ($tag) => [
'id' => $tag->id,
'title' => $tag->name,
'tag' => $tag->slug,
'color' => $tag->color,
'category' => $category,
])
->values();
if ($selectedTags->isNotEmpty()) {
$query->whereHas('tags', function ($q) use ($selectedTags) {
$q->whereIn('documentable_id', $selectedTags->map->id->all());
});
$selectedFilters['tags'] = $selectedTags;
}
$selectedYears = collect($data['filters']['years'] ?? '')
->map(fn (string $label) => YearsEnum::makeFromLabel(Str::replace('-', '/', $label)))
->filter()
->map(fn($year) => [
'title' => $year->label(),
'tag' => Str::replace('/', '-', $year->label()),
'value' => $year->value,
'category' => $category,
])
->values();
if ($selectedYears->isNotEmpty()) {
foreach ($selectedYears->map->value->all() as $value) {
$query->where('exercice', $value);
}
$selectedFilters['years'] = $selectedYears;
}
$selectedOrder = collect($data['filters']['order'] ?? '')
->map(fn (string $label) => OrdersEnum::makeFromLabel($label))
->filter()
->map(fn($order) => [
'title' => trans($order->label()),
'tag' => $order->name(),
'category' => $category,
])
->values();
if ($selectedOrder->isNotEmpty()) {
$query->orderBy('published_at', $selectedOrder->map->tag->first());
$selectedFilters['order'] = $selectedOrder->all();
}
/** Sort columns with a query */
$this->sortQuery($query);
$filters = $this->getFilters('documents', $category, $publishedDocumentsTags, $query);
/** Custom pagination */
$documentsModel = $query->paginate($perPage, ['*'], 'page', $data['page'] ?? 1);
return response()->json([
'pagination' => [
'total' => $documentsModel->total(),
'nbItems' => count($documentsModel->items()),
'currentPage' => $documentsModel->currentPage(),
'lastPage' => $documentsModel->lastPage(),
'hasMore' => $documentsModel->currentPage() < $documentsModel->lastPage(),
],
'filters' => view('components.front.posts.filters-dropdowns', ['filters' => $filters])->render(),
'selectedFilters' => view('components.front.posts.selected-filters', ['selectedFilters' => $selectedFilters])->render(),
'news' => view('components.front.posts.documents', ['documentsList' => $documentsModel->items()])->render()
]);
}
}