Configured swagger-php for documentation at /docs, probably needs a refactor lol; paginated searchAlbums to fix limit bug with null filters.

This commit is contained in:
boris committed 2026-02-27 20:15:57 +00:00
1 parent 56dea097d6
commit c1b1c2f372
19 files changed
+840 -273

No files matched your search

+118 -6
View File
@@ -9,6 +9,7 @@ use App\Repository\AlbumRepository;
use App\Repository\ReviewRepository;
use Doctrine\ORM\EntityManagerInterface;
use FOS\RestBundle\Controller\AbstractFOSRestController;
use OpenApi\Attributes as OA;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
@@ -25,6 +26,18 @@ class ReviewApiController extends AbstractFOSRestController
}
#[Route('', name: 'api_v1_review_index', methods: ['GET'])]
#[OA\Get(
path: '/api/v1/reviews',
operationId: 'api_v1_review_index',
summary: 'List latest reviews',
tags: ['Reviews'],
parameters: [
new OA\Parameter(name: 'limit', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 50)),
],
responses: [
new OA\Response(response: 200, description: 'Review list', content: new OA\JsonContent(type: 'object')),
]
)]
public function index(Request $request): Response
{
$limit = max(1, min(100, (int) $request->query->get('limit', 50)));
@@ -36,6 +49,18 @@ class ReviewApiController extends AbstractFOSRestController
}
#[Route('/{id}', name: 'api_v1_review_show', requirements: ['id' => '\\d+'], methods: ['GET'])]
#[OA\Get(
path: '/api/v1/reviews/{id}',
operationId: 'api_v1_review_show',
summary: 'Get a review by ID',
tags: ['Reviews'],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(response: 200, description: 'Review details', content: new OA\JsonContent(type: 'object')),
]
)]
public function show(Review $review): Response
{
return $this->handleView($this->view(['data' => $this->serializeReview($review)], Response::HTTP_OK));
@@ -43,6 +68,31 @@ class ReviewApiController extends AbstractFOSRestController
#[Route('', name: 'api_v1_review_create', methods: ['POST'])]
#[IsGranted('ROLE_USER')]
#[OA\Post(
path: '/api/v1/reviews',
operationId: 'api_v1_review_create',
summary: 'Create a review',
tags: ['Reviews'],
security: [['bearerAuth' => []]],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['album_id', 'title', 'content', 'rating'],
properties: [
new OA\Property(property: 'album_id', type: 'string'),
new OA\Property(property: 'title', type: 'string'),
new OA\Property(property: 'content', type: 'string'),
new OA\Property(property: 'rating', type: 'integer', minimum: 1, maximum: 10),
]
)
),
responses: [
new OA\Response(response: 201, description: 'Review created', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 400, description: 'Validation failed', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 401, description: 'JWT required', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 404, description: 'Album not found', content: new OA\JsonContent(type: 'object')),
]
)]
public function create(Request $request): Response
{
$payload = $this->readJsonPayload($request);
@@ -88,6 +138,58 @@ class ReviewApiController extends AbstractFOSRestController
#[Route('/{id}', name: 'api_v1_review_update', requirements: ['id' => '\\d+'], methods: ['PUT', 'PATCH'])]
#[IsGranted('ROLE_USER')]
#[OA\Put(
path: '/api/v1/reviews/{id}',
operationId: 'api_v1_review_update_put',
summary: 'Replace a review',
tags: ['Reviews'],
security: [['bearerAuth' => []]],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
properties: [
new OA\Property(property: 'title', type: 'string'),
new OA\Property(property: 'content', type: 'string'),
new OA\Property(property: 'rating', type: 'integer', minimum: 1, maximum: 10),
]
)
),
responses: [
new OA\Response(response: 200, description: 'Review updated', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 400, description: 'Validation failed', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 401, description: 'JWT required', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 403, description: 'Forbidden', content: new OA\JsonContent(type: 'object')),
]
)]
#[OA\Patch(
path: '/api/v1/reviews/{id}',
operationId: 'api_v1_review_update_patch',
summary: 'Partially update a review',
tags: ['Reviews'],
security: [['bearerAuth' => []]],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
properties: [
new OA\Property(property: 'title', type: 'string'),
new OA\Property(property: 'content', type: 'string'),
new OA\Property(property: 'rating', type: 'integer', minimum: 1, maximum: 10),
]
)
),
responses: [
new OA\Response(response: 200, description: 'Review updated', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 400, description: 'Validation failed', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 401, description: 'JWT required', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 403, description: 'Forbidden', content: new OA\JsonContent(type: 'object')),
]
)]
public function update(Review $review, Request $request): Response
{
$this->denyAccessUnlessGranted('REVIEW_EDIT', $review);
@@ -131,6 +233,21 @@ class ReviewApiController extends AbstractFOSRestController
#[Route('/{id}', name: 'api_v1_review_delete', requirements: ['id' => '\\d+'], methods: ['DELETE'])]
#[IsGranted('ROLE_USER')]
#[OA\Delete(
path: '/api/v1/reviews/{id}',
operationId: 'api_v1_review_delete',
summary: 'Delete a review',
tags: ['Reviews'],
security: [['bearerAuth' => []]],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(response: 204, description: 'Review deleted'),
new OA\Response(response: 401, description: 'JWT required', content: new OA\JsonContent(type: 'object')),
new OA\Response(response: 403, description: 'Forbidden', content: new OA\JsonContent(type: 'object')),
]
)]
public function delete(Review $review): Response
{
$this->denyAccessUnlessGranted('REVIEW_DELETE', $review);
@@ -161,7 +278,7 @@ class ReviewApiController extends AbstractFOSRestController
'display_name' => $review->getAuthor()?->getDisplayName(),
],
'album' => [
'id' => $album?->getSource() === 'user' ? $album?->getLocalId() : $album?->getExternalId(),
'id' => $album?->getExternalId(),
'name' => $album?->getName(),
'source' => $album?->getSource(),
],
@@ -174,11 +291,6 @@ class ReviewApiController extends AbstractFOSRestController
return null;
}
$local = $this->albumRepository->findOneByLocalId($albumId);
if ($local instanceof Album) {
return $local;
}
return $this->albumRepository->findOneByExternalId($albumId);
}