180 lines
5.3 KiB
PHP
180 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Forum;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class ForumController extends Controller
|
|
{
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$query = Forum::query();
|
|
|
|
$parentParam = $request->query('parent');
|
|
if (is_array($parentParam) && array_key_exists('exists', $parentParam)) {
|
|
$exists = filter_var($parentParam['exists'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
if ($exists === false) {
|
|
$query->whereNull('parent_id');
|
|
} elseif ($exists === true) {
|
|
$query->whereNotNull('parent_id');
|
|
}
|
|
} elseif (is_string($parentParam)) {
|
|
$parentId = $this->parseIriId($parentParam);
|
|
if ($parentId !== null) {
|
|
$query->where('parent_id', $parentId);
|
|
}
|
|
}
|
|
|
|
if ($request->filled('type')) {
|
|
$query->where('type', $request->query('type'));
|
|
}
|
|
|
|
$forums = $query
|
|
->orderBy('position')
|
|
->orderBy('name')
|
|
->get()
|
|
->map(fn (Forum $forum) => $this->serializeForum($forum));
|
|
|
|
return response()->json($forums);
|
|
}
|
|
|
|
public function show(Forum $forum): JsonResponse
|
|
{
|
|
return response()->json($this->serializeForum($forum));
|
|
}
|
|
|
|
public function store(Request $request): JsonResponse
|
|
{
|
|
$data = $request->validate([
|
|
'name' => ['required', 'string', 'max:100'],
|
|
'description' => ['nullable', 'string'],
|
|
'type' => ['required', Rule::in(['category', 'forum'])],
|
|
'parent' => ['nullable', 'string'],
|
|
]);
|
|
|
|
$parentId = $this->parseIriId($data['parent'] ?? null);
|
|
|
|
if ($parentId) {
|
|
$parent = Forum::findOrFail($parentId);
|
|
if ($parent->type !== 'category') {
|
|
return response()->json(['message' => 'Parent must be a category.'], 422);
|
|
}
|
|
}
|
|
|
|
$position = Forum::where('parent_id', $parentId)->max('position');
|
|
|
|
$forum = Forum::create([
|
|
'name' => $data['name'],
|
|
'description' => $data['description'] ?? null,
|
|
'type' => $data['type'],
|
|
'parent_id' => $parentId,
|
|
'position' => ($position ?? 0) + 1,
|
|
]);
|
|
|
|
return response()->json($this->serializeForum($forum), 201);
|
|
}
|
|
|
|
public function update(Request $request, Forum $forum): JsonResponse
|
|
{
|
|
$data = $request->validate([
|
|
'name' => ['sometimes', 'required', 'string', 'max:100'],
|
|
'description' => ['nullable', 'string'],
|
|
'type' => ['sometimes', Rule::in(['category', 'forum'])],
|
|
'parent' => ['nullable', 'string'],
|
|
]);
|
|
|
|
$parentId = $this->parseIriId($data['parent'] ?? null);
|
|
|
|
if (array_key_exists('parent', $data)) {
|
|
if ($parentId) {
|
|
$parent = Forum::findOrFail($parentId);
|
|
if ($parent->type !== 'category') {
|
|
return response()->json(['message' => 'Parent must be a category.'], 422);
|
|
}
|
|
}
|
|
$forum->parent_id = $parentId;
|
|
}
|
|
|
|
if (array_key_exists('name', $data)) {
|
|
$forum->name = $data['name'];
|
|
}
|
|
|
|
if (array_key_exists('description', $data)) {
|
|
$forum->description = $data['description'];
|
|
}
|
|
|
|
if (array_key_exists('type', $data)) {
|
|
$forum->type = $data['type'];
|
|
}
|
|
|
|
$forum->save();
|
|
|
|
return response()->json($this->serializeForum($forum));
|
|
}
|
|
|
|
public function destroy(Forum $forum): JsonResponse
|
|
{
|
|
$forum->delete();
|
|
|
|
return response()->json(null, 204);
|
|
}
|
|
|
|
public function reorder(Request $request): JsonResponse
|
|
{
|
|
$data = $request->validate([
|
|
'parentId' => ['nullable'],
|
|
'orderedIds' => ['required', 'array'],
|
|
'orderedIds.*' => ['integer'],
|
|
]);
|
|
|
|
$parentId = $data['parentId'] ?? null;
|
|
if ($parentId === '' || $parentId === 'null') {
|
|
$parentId = null;
|
|
} elseif ($parentId !== null) {
|
|
$parentId = (int) $parentId;
|
|
}
|
|
|
|
foreach ($data['orderedIds'] as $index => $forumId) {
|
|
Forum::where('id', $forumId)
|
|
->where('parent_id', $parentId)
|
|
->update(['position' => $index + 1]);
|
|
}
|
|
|
|
return response()->json(['status' => 'ok']);
|
|
}
|
|
|
|
private function parseIriId(?string $value): ?int
|
|
{
|
|
if (!$value) {
|
|
return null;
|
|
}
|
|
|
|
if (preg_match('#/forums/(\d+)$#', $value, $matches)) {
|
|
return (int) $matches[1];
|
|
}
|
|
|
|
if (is_numeric($value)) {
|
|
return (int) $value;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function serializeForum(Forum $forum): array
|
|
{
|
|
return [
|
|
'id' => $forum->id,
|
|
'name' => $forum->name,
|
|
'description' => $forum->description,
|
|
'type' => $forum->type,
|
|
'parent' => $forum->parent_id ? "/api/forums/{$forum->parent_id}" : null,
|
|
'position' => $forum->position,
|
|
'created_at' => $forum->created_at?->toIso8601String(),
|
|
'updated_at' => $forum->updated_at?->toIso8601String(),
|
|
];
|
|
}
|
|
}
|