From a3963d093e7fffa1dcd32545fd4f8e19d57fad12 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Thu, 4 Jun 2026 22:00:51 +0000 Subject: [PATCH] List and add ratings --- src/Controller/Api/RatingController.php | 62 +++++++++++++++ src/Entity/Subject.php | 2 +- src/Factory/RatingFactory.php | 2 +- src/Factory/SubjectFactory.php | 2 +- src/Repository/RatingRepository.php | 19 +++++ src/Repository/SubjectRepository.php | 9 +++ .../Controller/Api/RatingControllerTest.php | 79 +++++++++++++++++++ .../Controller/Api/SubjectControllerTest.php | 0 8 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 src/Controller/Api/RatingController.php create mode 100644 tests/Application/Controller/Api/RatingControllerTest.php rename tests/{Unit => Application}/Controller/Api/SubjectControllerTest.php (100%) diff --git a/src/Controller/Api/RatingController.php b/src/Controller/Api/RatingController.php new file mode 100644 index 0000000..cdd6b93 --- /dev/null +++ b/src/Controller/Api/RatingController.php @@ -0,0 +1,62 @@ +json($output->success([ + 'ratings' => array_map( + fn(Rating $rating) => [ + 'id' => $rating->getId(), + 'score' => $rating->getScore(), + 'subject' => [ + 'id' => $rating->getSubject()->getId(), + 'name' => $rating->getSubject()->getName(), + ], + ], + $repo->findAll() + ), + ])); + } + + #[Route('/api/ratings', methods: ['POST'])] + public function create( + Request $request, + EntityManagerInterface $em, + OutputService $output, + SubjectRepository $subjectRepository, + ): JsonResponse { + $subject = $subjectRepository->findById($request->getPayload()->get('subject_id')); + + if ($subject === null) { + return $this->json( + $output->error(["UNKNOWN_SUBJECT"]) + ); + } + + $rating = new Rating(); + $rating->setSubject($subject); + $rating->setScore($request->getPayload()->get('score')); + + $em->persist($rating); + $em->flush(); + + return $this->json(null, 201); + } +} diff --git a/src/Entity/Subject.php b/src/Entity/Subject.php index 560c771..79a95cf 100644 --- a/src/Entity/Subject.php +++ b/src/Entity/Subject.php @@ -29,7 +29,7 @@ abstract class Subject /** * @var Collection */ - #[ORM\OneToMany(targetEntity: Rating::class, mappedBy: 'subject_id', orphanRemoval: true)] + #[ORM\OneToMany(targetEntity: Rating::class, mappedBy: 'subject', orphanRemoval: true)] private Collection $ratings; public function __construct() diff --git a/src/Factory/RatingFactory.php b/src/Factory/RatingFactory.php index 22f8f43..f0ee195 100644 --- a/src/Factory/RatingFactory.php +++ b/src/Factory/RatingFactory.php @@ -36,7 +36,7 @@ final class RatingFactory extends PersistentObjectFactory protected function defaults(): array|callable { return [ - 'subject_id' => SubjectFactory::new(), + 'subject' => SubjectFactory::new(), ]; } diff --git a/src/Factory/SubjectFactory.php b/src/Factory/SubjectFactory.php index bbd240f..9e63740 100644 --- a/src/Factory/SubjectFactory.php +++ b/src/Factory/SubjectFactory.php @@ -37,7 +37,7 @@ final class SubjectFactory extends PersistentObjectFactory protected function defaults(): array|callable { return [ - 'name' => self::faker()->text(255), + 'name' => self::faker()->text(10), ]; } diff --git a/src/Repository/RatingRepository.php b/src/Repository/RatingRepository.php index 95754b2..2680716 100644 --- a/src/Repository/RatingRepository.php +++ b/src/Repository/RatingRepository.php @@ -3,6 +3,7 @@ namespace App\Repository; use App\Entity\Rating; +use App\Entity\Subject; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; @@ -16,6 +17,24 @@ class RatingRepository extends ServiceEntityRepository parent::__construct($registry, Rating::class); } + public function findById(int $id): ?Rating + { + return $this->createQueryBuilder('r') + ->where('r.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->getOneOrNullResult(); + } + + public function findAllBySubject(Subject $subject): array + { + return $this->createQueryBuilder('r') + ->where('r.subject = :subject') + ->setParameter('subject', $subject) + ->getQuery() + ->getResult(); + } + // /** // * @return Rating[] Returns an array of Rating objects // */ diff --git a/src/Repository/SubjectRepository.php b/src/Repository/SubjectRepository.php index 3ed365b..5d47894 100644 --- a/src/Repository/SubjectRepository.php +++ b/src/Repository/SubjectRepository.php @@ -16,6 +16,15 @@ class SubjectRepository extends ServiceEntityRepository parent::__construct($registry, Subject::class); } + public function findById(int $id): ?Subject + { + return $this->createQueryBuilder('s') + ->where('s.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->getOneOrNullResult(); + } + // /** // * @return Subject[] Returns an array of Subject objects // */ diff --git a/tests/Application/Controller/Api/RatingControllerTest.php b/tests/Application/Controller/Api/RatingControllerTest.php new file mode 100644 index 0000000..01ed41b --- /dev/null +++ b/tests/Application/Controller/Api/RatingControllerTest.php @@ -0,0 +1,79 @@ +loginUser($user); + + $subject = RestaurantFactory::createOne([ + 'createdBy' => $user, + ]); + + $ratings = RatingFactory::createMany(5, [ + 'subject' => $subject, + ]); + + $client->request( + 'GET', + '/api/ratings', + server: ['CONTENT_TYPE' => 'application/json'], + content: json_encode(['name' => 'Riviera']), + ); + + $data = json_decode($client->getResponse()->getContent(), true); + + $this->assertResponseIsSuccessful(); + $this->assertCount(5, $data['payload']['ratings']); + } + + public function testCreate(): void + { + $client = static::createClient(); + + $repo = static::getContainer()->get(RatingRepository::class); + + $user = UserFactory::createOne(); + $client->loginUser($user); + + $subject = RestaurantFactory::createOne([ + 'createdBy' => $user, + ]); + + $client->request( + 'POST', + '/api/ratings', + server: ['CONTENT_TYPE' => 'application/json'], + content: json_encode([ + 'subject_id' => $subject->getId(), + 'score' => 8, + ]), + ); + + $this->assertResponseIsSuccessful(); + $this->assertResponseStatusCodeSame(201); + $this->assertCount(1, $repo->findAll()); + + $ratings = static::getContainer() + ->get(RatingRepository::class) + ->findAllBySubject($subject); + + $this->assertNotNull($ratings); + $this->assertCount(1, $ratings); + $this->assertInstanceOf(Rating::class, $ratings[0]); + } +} diff --git a/tests/Unit/Controller/Api/SubjectControllerTest.php b/tests/Application/Controller/Api/SubjectControllerTest.php similarity index 100% rename from tests/Unit/Controller/Api/SubjectControllerTest.php rename to tests/Application/Controller/Api/SubjectControllerTest.php