309 lines
10 KiB
PHP
309 lines
10 KiB
PHP
|
<?php
|
||
|
|
||
|
declare(strict_types=1);
|
||
|
|
||
|
namespace App\Http\Controllers;
|
||
|
|
||
|
use App\Http\Requests\Post\DestroyPostRequest;
|
||
|
use App\Http\Requests\Post\ListPostRequest;
|
||
|
use App\Http\Requests\Post\ShowPostRequest;
|
||
|
use App\Http\Requests\Post\StorePostRequest;
|
||
|
use App\Http\Requests\Post\UpdatePostRequest;
|
||
|
use App\Http\Resources\PaginableResource;
|
||
|
use App\Http\Resources\PostCollection;
|
||
|
use App\Http\Resources\PostResource;
|
||
|
use App\Services\Post\PostServiceInterface;
|
||
|
use Illuminate\Http\JsonResponse;
|
||
|
use OpenApi\Annotations as OA;
|
||
|
|
||
|
final class PostController extends Controller
|
||
|
{
|
||
|
public function __construct(
|
||
|
private readonly PostServiceInterface $postService,
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @OA\Get(
|
||
|
* path="/api/v1/posts/{page}",
|
||
|
* summary="List all posts",
|
||
|
* description="Fetch a paginated list of all posts.",
|
||
|
* tags={"Posts"},
|
||
|
* @OA\Parameter(
|
||
|
* name="direction",
|
||
|
* in="query",
|
||
|
* description="Order posts by ascending or descending",
|
||
|
* required=false,
|
||
|
* @OA\Schema(
|
||
|
* type="string",
|
||
|
* enum={"asc", "desc"},
|
||
|
* example="asc"
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Parameter(
|
||
|
* name="order",
|
||
|
* in="query",
|
||
|
* description="Order posts by column name",
|
||
|
* required=false,
|
||
|
* @OA\Schema(
|
||
|
* type="string",
|
||
|
* example="title"
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Parameter(
|
||
|
* name="title",
|
||
|
* in="query",
|
||
|
* description="Filter posts by title",
|
||
|
* required=false,
|
||
|
* @OA\Schema(
|
||
|
* type="string",
|
||
|
* example="Sample Post"
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Parameter(
|
||
|
* name="page",
|
||
|
* in="path",
|
||
|
* description="Pagination page number",
|
||
|
* required=false,
|
||
|
* @OA\Schema(
|
||
|
* type="integer",
|
||
|
* example=1
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=200,
|
||
|
* description="Successful response",
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(
|
||
|
* property="items",
|
||
|
* ref="#/components/schemas/PostCollection"
|
||
|
* ),
|
||
|
* @OA\Property(
|
||
|
* property="meta",
|
||
|
* type="object",
|
||
|
* description="Pagination metadata",
|
||
|
* ref="#/components/schemas/PaginableResourceMeta"
|
||
|
* )
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=422,
|
||
|
* description="Validation error",
|
||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError")
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=429,
|
||
|
* description="Rate limiting. Try again later.",
|
||
|
* )
|
||
|
* )
|
||
|
*/
|
||
|
public function list(ListPostRequest $request, int $page): JsonResponse
|
||
|
{
|
||
|
$posts = $this->postService->fetchPosts(
|
||
|
$page,
|
||
|
$request->filters(),
|
||
|
$request->order()
|
||
|
);
|
||
|
return response()->json(PaginableResource::make($posts, PostCollection::class));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @OA\Post(
|
||
|
* path="/api/v1/posts",
|
||
|
* operationId="storePost",
|
||
|
* tags={"Posts"},
|
||
|
* summary="Create a new post",
|
||
|
* description="Creates a new post in the system based on the provided input data.",
|
||
|
* @OA\RequestBody(
|
||
|
* description="Payload for creating a new post",
|
||
|
* required=true,
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(property="title", type="string", maxLength=255, example="My First Post"),
|
||
|
* @OA\Property(property="content", type="string", example="This is the content of my first post."),
|
||
|
* @OA\Property(property="category_id", type="integer", example=1),
|
||
|
* @OA\Property(property="tags", type="array", @OA\Items(type="string", example="Laravel")),
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=201,
|
||
|
* description="Post successfully created",
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(property="status", type="string", example="success"),
|
||
|
* @OA\Property(property="message", type="string", example="Post created successfully."),
|
||
|
* @OA\Property(
|
||
|
* property="data",
|
||
|
* type="object",
|
||
|
* ref="#/components/schemas/PostResource"
|
||
|
* )
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=422,
|
||
|
* description="Validation error",
|
||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError")
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=429,
|
||
|
* description="Rate limiting. Try again later.",
|
||
|
* )
|
||
|
* )
|
||
|
*/
|
||
|
public function store(StorePostRequest $request): JsonResponse
|
||
|
{
|
||
|
return response()->json(PostResource::make($this->postService->storePost($request->all())), 201);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @OA\Get(
|
||
|
* path="/api/v1/posts/{id}",
|
||
|
* operationId="getPostById",
|
||
|
* tags={"Posts"},
|
||
|
* summary="Get a specific post by ID",
|
||
|
* description="Returns a specific post identified by its unique ID.",
|
||
|
* @OA\Parameter(
|
||
|
* name="id",
|
||
|
* in="path",
|
||
|
* description="ID of the post to retrieve",
|
||
|
* required=true,
|
||
|
* @OA\Schema(type="integer", example=1)
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=200,
|
||
|
* description="Post data retrieved successfully",
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(property="status", type="string", example="success"),
|
||
|
* @OA\Property(
|
||
|
* property="data",
|
||
|
* type="object",
|
||
|
* ref="#/components/schemas/PostResource"
|
||
|
* )
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=404,
|
||
|
* description="Post not found",
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=429,
|
||
|
* description="Rate limiting. Try again later.",
|
||
|
* )
|
||
|
* )
|
||
|
*/
|
||
|
public function show(ShowPostRequest $request, int $id): JsonResponse
|
||
|
{
|
||
|
$post = $this->postService->findPost($id);
|
||
|
|
||
|
if ($post === null) {
|
||
|
return response()->json(null, 404);
|
||
|
}
|
||
|
|
||
|
return response()->json(PostResource::make($post));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @OA\Put(
|
||
|
* path="/api/v1/post/{id}",
|
||
|
* operationId="updatePost",
|
||
|
* tags={"Posts"},
|
||
|
* summary="Update a specific post by ID",
|
||
|
* description="Updates specific fields of a post identified by its unique ID.",
|
||
|
* @OA\Parameter(
|
||
|
* name="id",
|
||
|
* in="path",
|
||
|
* description="ID of the post to update",
|
||
|
* required=true,
|
||
|
* @OA\Schema(type="integer", example=1)
|
||
|
* ),
|
||
|
* @OA\RequestBody(
|
||
|
* description="Payload for updating a post",
|
||
|
* required=true,
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(property="title", type="string", maxLength=255, example="Updated Title"),
|
||
|
* @OA\Property(property="content", type="string", example="Updated content of the post."),
|
||
|
* @OA\Property(property="category_id", type="integer", example=2),
|
||
|
* @OA\Property(property="tags", type="array", @OA\Items(type="string", example="Laravel"))
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=200,
|
||
|
* description="Post data updated sucessfully",
|
||
|
* @OA\JsonContent(
|
||
|
* type="object",
|
||
|
* @OA\Property(property="status", type="string", example="success"),
|
||
|
* @OA\Property(
|
||
|
* property="data",
|
||
|
* type="object",
|
||
|
* ref="#/components/schemas/PostResource"
|
||
|
* )
|
||
|
* )
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=404,
|
||
|
* description="Post not found",
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=422,
|
||
|
* description="Validation error",
|
||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError")
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=429,
|
||
|
* description="Rate limiting. Try again later.",
|
||
|
* )
|
||
|
* )
|
||
|
*/
|
||
|
public function update(UpdatePostRequest $request, int $id): JsonResponse
|
||
|
{
|
||
|
$post = $this->postService->updatePost($request->all(), $id);
|
||
|
|
||
|
if ($post === null) {
|
||
|
return response()->json(null, 404);
|
||
|
}
|
||
|
|
||
|
return response()->json(PostResource::make($post));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @OA\Delete(
|
||
|
* path="/api/v1/post/{id}",
|
||
|
* operationId="deletePost",
|
||
|
* tags={"Posts"},
|
||
|
* summary="Delete a specific post by ID",
|
||
|
* description="Deletes a specific post identified by its unique ID. This operation is irreversible.",
|
||
|
* @OA\Parameter(
|
||
|
* name="id",
|
||
|
* in="path",
|
||
|
* description="ID of the post to delete",
|
||
|
* required=true,
|
||
|
* @OA\Schema(type="integer", example=1)
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=204,
|
||
|
* description="Post successfully deleted",
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=404,
|
||
|
* description="Post not found",
|
||
|
* ),
|
||
|
* @OA\Response(
|
||
|
* response=429,
|
||
|
* description="Rate limiting. Try again later.",
|
||
|
* )
|
||
|
* )
|
||
|
*/
|
||
|
public function destroy(DestroyPostRequest $post, int $id): JsonResponse
|
||
|
{
|
||
|
$isSuccessfullyDeleted = $this->postService->deletePost($id);
|
||
|
return match ($isSuccessfullyDeleted) {
|
||
|
false => response()->json(null, 404),
|
||
|
true => response()->json(null, 204),
|
||
|
};
|
||
|
}
|
||
|
}
|