diff --git a/src/Controller/Api/SubjectController.php b/src/Controller/Api/SubjectController.php index ec09876..90259ba 100644 --- a/src/Controller/Api/SubjectController.php +++ b/src/Controller/Api/SubjectController.php @@ -54,6 +54,22 @@ class SubjectController extends AbstractController return $this->json(null, 201); } + #[Route('/api/subjects/{id}', methods: ['GET'])] + public function show( + int $id, + SubjectRepository $repository, + SubjectPresenter $presenter, + OutputService $output, + ): JsonResponse { + $subject = $repository->find($id); + + if ($subject === null) { + return $this->json($output->error(['UNKNOWN_SUBJECT']), 404); + } + + return $this->json($output->success(['subject' => $presenter->present($subject)])); + } + #[Route('/api/subjects/{id}', methods: ['PATCH'])] public function update( int $id, diff --git a/src/Factory/RatingFactory.php b/src/Factory/RatingFactory.php index 1b92b0f..499c687 100644 --- a/src/Factory/RatingFactory.php +++ b/src/Factory/RatingFactory.php @@ -32,6 +32,8 @@ final class RatingFactory extends PersistentObjectFactory protected function defaults(): array|callable { return [ + 'score' => self::faker()->numberBetween(1, 5), + 'note' => self::faker()->optional()->sentence() ?? '', 'subject' => RestaurantFactory::new(), 'user' => UserFactory::new(), ]; diff --git a/src/Presenter/SubjectPresenter.php b/src/Presenter/SubjectPresenter.php index 30e9bb3..b6cd24b 100644 --- a/src/Presenter/SubjectPresenter.php +++ b/src/Presenter/SubjectPresenter.php @@ -15,6 +15,10 @@ class SubjectPresenter */ public function present(Subject $subject): array { + $ratings = $subject->getRatings()->toArray(); + + usort($ratings, fn($a, $b) => $b->getCreatedAt() <=> $a->getCreatedAt()); + return [ 'id' => $subject->getId(), 'name' => $subject->getName(), @@ -24,13 +28,32 @@ class SubjectPresenter 'id' => $subject->getCreatedBy()->getId(), 'email' => $subject->getCreatedBy()->getEmail(), ], + 'ratingCount' => count($ratings), + 'averageScore' => $this->computeAverage($ratings), 'ratings' => array_map( fn($r) => $this->ratingPresenter->present($r), - $subject->getRatings()->toArray() + $ratings ), ]; } + /** + * @param array<\App\Entity\Rating> $ratings + */ + private function computeAverage(array $ratings): ?float + { + $scores = array_filter( + array_map(fn($r) => $r->getScore(), $ratings), + fn($s) => $s !== null + ); + + if (count($scores) === 0) { + return null; + } + + return round(array_sum($scores) / count($scores), 1); + } + /** * @param iterable $subjects * @return array> diff --git a/tests/Application/Controller/Api/SubjectControllerTest.php b/tests/Application/Controller/Api/SubjectControllerTest.php index d5c6147..1f03929 100644 --- a/tests/Application/Controller/Api/SubjectControllerTest.php +++ b/tests/Application/Controller/Api/SubjectControllerTest.php @@ -4,6 +4,7 @@ namespace App\Tests\Application\Controller\Api; use App\Entity\Restaurant; use App\Entity\Subject; +use App\Factory\RatingFactory; use App\Factory\RestaurantFactory; use App\Factory\UserFactory; use App\Repository\SubjectRepository; @@ -39,6 +40,38 @@ class SubjectControllerTest extends WebTestCase $this->assertNotNull($subject['longitude']); } + public function testShow(): void + { + $client = static::createClient(); + + $user = UserFactory::createOne(); + $client->loginUser($user); + + $subject = RestaurantFactory::createOne(['createdBy' => $user]); + + RatingFactory::createOne(['subject' => $subject, 'score' => 4, 'user' => $user]); + RatingFactory::createOne(['subject' => $subject, 'score' => 2, 'user' => UserFactory::createOne()]); + + $client->request('GET', '/api/subjects/' . $subject->getId(), server: ['CONTENT_TYPE' => 'application/json']); + + $data = json_decode($client->getResponse()->getContent(), true); + + $this->assertResponseIsSuccessful(); + $this->assertSame($subject->getId(), $data['payload']['subject']['id']); + $this->assertSame($subject->getName(), $data['payload']['subject']['name']); + $this->assertCount(2, $data['payload']['subject']['ratings']); + $this->assertSame(2, $data['payload']['subject']['ratingCount']); + $this->assertEquals(3.0, $data['payload']['subject']['averageScore']); + + $rating = $data['payload']['subject']['ratings'][0]; + $this->assertArrayHasKey('id', $rating); + $this->assertArrayHasKey('score', $rating); + $this->assertArrayHasKey('note', $rating); + $this->assertArrayHasKey('createdAt', $rating); + $this->assertArrayHasKey('user', $rating); + $this->assertArrayHasKey('id', $rating['user']); + } + public function testCreate(): void { $client = static::createClient();