Skip to content

Commit 4315909

Browse files
feat: use ApiProperty::uriTemplate option
1 parent f720071 commit 4315909

File tree

5 files changed

+16
-26
lines changed

5 files changed

+16
-26
lines changed

api/src/Entity/Book.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use App\Repository\BookRepository;
2121
use App\State\Processor\BookPersistProcessor;
2222
use App\State\Processor\BookRemoveProcessor;
23+
use Doctrine\Common\Collections\ArrayCollection;
24+
use Doctrine\Common\Collections\Collection;
2325
use Doctrine\DBAL\Types\Types;
2426
use Doctrine\ORM\Mapping as ORM;
2527
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
@@ -159,14 +161,18 @@ class Book
159161
/**
160162
* An IRI of reviews.
161163
*
164+
* @var Collection<int, Review>
165+
*
162166
* @see https://schema.org/reviews
163167
*/
164168
#[ApiProperty(
165169
types: ['https://schema.org/reviews'],
166-
example: '/books/6acacc80-8321-4d83-9b02-7f2c7bf6eb1d/reviews'
170+
example: '/books/6acacc80-8321-4d83-9b02-7f2c7bf6eb1d/reviews',
171+
uriTemplate: '/books/{bookId}/reviews{._format}'
167172
)]
168173
#[Groups(groups: ['Book:read', 'Bookmark:read'])]
169-
public ?string $reviews = null;
174+
#[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book')]
175+
public Collection $reviews;
170176

171177
/**
172178
* The overall rating, based on a collection of reviews or ratings, of the item.
@@ -180,6 +186,11 @@ class Book
180186
#[Groups(groups: ['Book:read', 'Book:read:admin', 'Bookmark:read'])]
181187
public ?int $rating = null;
182188

189+
public function __construct()
190+
{
191+
$this->reviews = new ArrayCollection();
192+
}
193+
183194
public function getId(): ?Uuid
184195
{
185196
return $this->id;

api/src/Entity/Review.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class Review
174174
#[ApiProperty(types: ['https://schema.org/itemReviewed'])]
175175
#[Assert\NotNull]
176176
#[Groups(groups: ['Review:read', 'Review:write:admin'])]
177-
#[ORM\ManyToOne(targetEntity: Book::class)]
177+
#[ORM\ManyToOne(targetEntity: Book::class, inversedBy: 'reviews')]
178178
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
179179
public ?Book $book = null;
180180

api/src/Serializer/BookNormalizer.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use App\Repository\ReviewRepository;
99
use Doctrine\Persistence\ObjectRepository;
1010
use Symfony\Component\DependencyInjection\Attribute\Autowire;
11-
use Symfony\Component\Routing\RouterInterface;
1211
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
1312
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
1413
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -21,7 +20,6 @@ final class BookNormalizer implements NormalizerInterface, NormalizerAwareInterf
2120
* @param ReviewRepository $repository
2221
*/
2322
public function __construct(
24-
private RouterInterface $router,
2523
#[Autowire(service: ReviewRepository::class)]
2624
private ObjectRepository $repository
2725
) {
@@ -32,9 +30,6 @@ public function __construct(
3230
*/
3331
public function normalize(mixed $object, ?string $format = null, array $context = []): array
3432
{
35-
$object->reviews = $this->router->generate('_api_/books/{bookId}/reviews{._format}_get_collection', [
36-
'bookId' => $object->getId(),
37-
]);
3833
$object->rating = $this->repository->getAverageRating($object);
3934

4035
return $this->normalizer->normalize($object, $format, [self::class => true] + $context);

api/tests/Serializer/BookNormalizerTest.php

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,22 @@
1111
use PHPUnit\Framework\Attributes\Test;
1212
use PHPUnit\Framework\MockObject\MockObject;
1313
use PHPUnit\Framework\TestCase;
14-
use Symfony\Component\Routing\RouterInterface;
1514
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
16-
use Symfony\Component\Uid\Uuid;
1715

1816
final class BookNormalizerTest extends TestCase
1917
{
2018
private MockObject|NormalizerInterface $normalizerMock;
21-
private MockObject|RouterInterface $routerMock;
2219
private MockObject|ReviewRepository $repositoryMock;
2320
private Book|MockObject $objectMock;
2421
private BookNormalizer $normalizer;
2522

2623
protected function setUp(): void
2724
{
2825
$this->normalizerMock = $this->createMock(NormalizerInterface::class);
29-
$this->routerMock = $this->createMock(RouterInterface::class);
3026
$this->repositoryMock = $this->createMock(ReviewRepository::class);
3127
$this->objectMock = $this->createMock(Book::class);
3228

33-
$this->normalizer = new BookNormalizer($this->routerMock, $this->repositoryMock);
29+
$this->normalizer = new BookNormalizer($this->repositoryMock);
3430
$this->normalizer->setNormalizer($this->normalizerMock);
3531
}
3632

@@ -56,20 +52,8 @@ public function itSupportsValidObjectClassAndContext(): void
5652
public function itNormalizesData(): void
5753
{
5854
$expectedObject = $this->objectMock;
59-
$expectedObject->reviews = '/books/a528046c-7ba1-4acc-bff2-b5390ab17d41/reviews';
6055
$expectedObject->rating = 3;
6156

62-
$this->objectMock
63-
->expects($this->once())
64-
->method('getId')
65-
->willReturn(Uuid::fromString('a528046c-7ba1-4acc-bff2-b5390ab17d41'))
66-
;
67-
$this->routerMock
68-
->expects($this->once())
69-
->method('generate')
70-
->with('_api_/books/{bookId}/reviews{._format}_get_collection', ['bookId' => 'a528046c-7ba1-4acc-bff2-b5390ab17d41'])
71-
->willReturn('/books/a528046c-7ba1-4acc-bff2-b5390ab17d41/reviews')
72-
;
7357
$this->repositoryMock
7458
->expects($this->once())
7559
->method('getAverageRating')

compose.override.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ services:
1515
environment:
1616
MERCURE_EXTRA_DIRECTIVES: demo
1717
# See https://xdebug.org/docs/all_settings#mode
18-
XDEBUG_MODE: debug
18+
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
1919
extra_hosts:
2020
# Ensure that host.docker.internal is correctly defined on Linux
2121
- host.docker.internal:host-gateway

0 commit comments

Comments
 (0)