<?php
namespace App\Controller;
use App\DataTransformer\VinOutputTransformer;
use App\Entity\Vin;
use App\Message\CheckVinMessage;
use App\Service\Vin\VinService;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
class VinController extends AbstractController
{
public function __construct(
private VinService $checkVin,
private SerializerInterface $serializer,
private EntityManagerInterface $em,
private VinOutputTransformer $outputTransformer,
private MessageBusInterface $bus,
) {
}
/**
* @OA\Response(
* response="201",
* description="Returns created vin",
* @Model(type=Vin::class, groups={"index"})
* ),
* @OA\Response(
* response="400",
* description="Wrong input data"
* ),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="vin", type="string", example="4GDDU03A8VD268007"),
* ),
* )
*/
#[Route('/api/vin', name: 'app_check_reports', methods: ['POST'], format: 'json')]
public function handleCheckReports(Request $request, RateLimiterFactory $anonymousApiLimiter): Response
{
$limiter = $anonymousApiLimiter->create($request->getClientIp());
if (!$limiter->consume()->isAccepted()) {
throw new BadRequestHttpException('Rate Limit Exceeded');
}
try {
$payload = \json_decode((string) $request->getContent(), true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new BadRequestHttpException(\sprintf('Bad request: %s', $e->getMessage()));
}
$vin = $payload['vin'] ?? null;
if ($vin === null) {
throw new BadRequestHttpException('Field: \'vin\' is required');
}
try {
$vin = \strtoupper($vin);
$vinInstance = $this->checkVin->getVin($vin);
$this->bus->dispatch(new CheckVinMessage($vinInstance));
} catch (\InvalidArgumentException $e) {
throw new BadRequestHttpException($e->getMessage());
}
return new Response($this->serializer->serialize(['vin' => $this->outputTransformer->transform($vinInstance)], 'json', ['groups' => 'index']), Response::HTTP_CREATED);
}
/**
* @OA\Response(
* response="200",
* description="Returns requested vin",
* @Model(type=Vin::class, groups={"index"})
* ),
* @OA\Response(
* response="400",
* description="Returns if vin is not found",
* ),
* @OA\Parameter(
* name="vin",
* in="path",
* required=true,
* @OA\Schema(type="string")
* ),
*/
#[Route('/api/vin/{vin}', name: 'app_get_vin', methods: ['GET'], format: 'json')]
public function handleGetVin(string $vin): Response
{
$vin = \strtoupper($vin);
$vinInstance = $this->em->getRepository(Vin::class)->findOneBy(['vin' => $vin]);
if (!$vinInstance instanceof Vin) {
throw new BadRequestHttpException(\sprintf('VIN (%s) was not found', $vin));
}
return new Response($this->serializer->serialize(['vin' => $this->outputTransformer->transform($vinInstance)], 'json', ['groups' => 'index']), Response::HTTP_OK);
}
}