Skip to content

Commit

Permalink
test: add tests with Mercure
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentchalamon committed Aug 7, 2023
1 parent 929625e commit f062fe7
Show file tree
Hide file tree
Showing 17 changed files with 704 additions and 41 deletions.
2 changes: 1 addition & 1 deletion api/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"ext-ctype": "*",
"ext-iconv": "*",
"ext-xml": "*",
"api-platform/core": "dev-fix/issues/5662",
"api-platform/core": "dev-demo",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.12",
Expand Down
23 changes: 11 additions & 12 deletions api/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 16 additions & 4 deletions api/src/Entity/Book.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use App\Enum\BookCondition;
use App\Repository\BookRepository;
use App\State\Processor\BookPersistProcessor;
use App\State\Processor\BookRemoveProcessor;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
Expand All @@ -39,6 +40,7 @@
itemUriTemplate: '/admin/books/{id}{._format}'
),
new Post(
// Mercure publish is done manually in MercureProcessor through BookPersistProcessor
processor: BookPersistProcessor::class,
itemUriTemplate: '/admin/books/{id}{._format}'
),
Expand All @@ -48,15 +50,21 @@
// https://github.com/api-platform/admin/issues/370
new Put(
uriTemplate: '/admin/books/{id}{._format}',
// Mercure publish is done manually in MercureProcessor through BookPersistProcessor
processor: BookPersistProcessor::class
),
new Delete(
uriTemplate: '/admin/books/{id}{._format}'
uriTemplate: '/admin/books/{id}{._format}',
// Mercure publish is done manually in MercureProcessor through BookRemoveProcessor
processor: BookRemoveProcessor::class
),
],
normalizationContext: ['groups' => ['Book:read:admin', 'Enum:read']],
normalizationContext: [
'item_uri_template' => '/admin/books/{id}{._format}',
'groups' => ['Book:read:admin', 'Enum:read'],
'skip_null_values' => true,
],
denormalizationContext: ['groups' => ['Book:write']],
mercure: true, // todo ensure mercure message is sent to "/books/*" too
security: 'is_granted("ROLE_ADMIN")'
)]
#[ApiResource(
Expand All @@ -67,7 +75,11 @@
),
new Get(),
],
normalizationContext: ['groups' => ['Book:read', 'Enum:read']]
normalizationContext: [
'item_uri_template' => '/books/{id}{._format}',
'groups' => ['Book:read', 'Enum:read'],
'skip_null_values' => true,
]
)]
#[ORM\Entity(repositoryClass: BookRepository::class)]
#[UniqueEntity(fields: ['book'])]
Expand Down
7 changes: 5 additions & 2 deletions api/src/Entity/Bookmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Repository\BookmarkRepository;
Expand All @@ -30,13 +30,16 @@
types: ['https://schema.org/BookmarkAction'],
operations: [
new GetCollection(),
new Get(),
new Delete(
security: 'is_granted("ROLE_USER") and object.user === user'
),
new Post(
processor: BookmarkPersistProcessor::class
),
],
normalizationContext: [
'groups' => ['Bookmark:read'],
'skip_null_values' => true,
IriTransformerNormalizer::CONTEXT_KEY => [
'book' => '/books/{id}{._format}',
],
Expand Down
26 changes: 20 additions & 6 deletions api/src/Entity/Review.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\NotExposed;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Repository\ReviewRepository;
use App\Serializer\IriTransformerNormalizer;
use App\State\Processor\ReviewPersistProcessor;
use App\State\Processor\ReviewRemoveProcessor;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
Expand All @@ -41,21 +43,26 @@
),
// https://github.com/api-platform/admin/issues/370
new Put(
uriTemplate: '/admin/reviews/{id}{._format}'
uriTemplate: '/admin/reviews/{id}{._format}',
// Mercure publish is done manually in MercureProcessor through ReviewPersistProcessor
processor: ReviewPersistProcessor::class
),
new Delete(
uriTemplate: '/admin/reviews/{id}{._format}'
uriTemplate: '/admin/reviews/{id}{._format}',
// Mercure publish is done manually in MercureProcessor through ReviewRemoveProcessor
processor: ReviewRemoveProcessor::class
),
],
normalizationContext: [
IriTransformerNormalizer::CONTEXT_KEY => [
'book' => '/admin/books/{id}{._format}',
'user' => '/admin/users/{id}{._format}',
],
'item_uri_template' => '/admin/reviews/{id}{._format}',
'skip_null_values' => true,
'groups' => ['Review:read', 'Review:read:admin'],
],
denormalizationContext: ['groups' => ['Review:write']],
mercure: true,
security: 'is_granted("ROLE_ADMIN")'
)]
#[ApiResource(
Expand All @@ -69,7 +76,7 @@
itemUriTemplate: '/books/{bookId}/reviews/{id}{._format}',
paginationClientItemsPerPage: true
),
new Get(
new NotExposed(
uriTemplate: '/books/{bookId}/reviews/{id}{._format}',
uriVariables: [
'bookId' => new Link(toProperty: 'book', fromClass: Book::class),
Expand All @@ -78,6 +85,7 @@
),
new Post(
security: 'is_granted("ROLE_USER")',
// Mercure publish is done manually in MercureProcessor through ReviewPersistProcessor
processor: ReviewPersistProcessor::class,
itemUriTemplate: '/books/{bookId}/reviews/{id}{._format}'
),
Expand All @@ -87,22 +95,28 @@
'bookId' => new Link(toProperty: 'book', fromClass: Book::class),
'id' => new Link(fromClass: Review::class),
],
security: 'is_granted("ROLE_USER") and user == object.user'
security: 'is_granted("ROLE_USER") and user == object.user',
// Mercure publish is done manually in MercureProcessor through ReviewPersistProcessor
processor: ReviewPersistProcessor::class
),
new Delete(
uriTemplate: '/books/{bookId}/reviews/{id}{._format}',
uriVariables: [
'bookId' => new Link(toProperty: 'book', fromClass: Book::class),
'id' => new Link(fromClass: Review::class),
],
security: 'is_granted("ROLE_USER") and user == object.user'
security: 'is_granted("ROLE_USER") and user == object.user',
// Mercure publish is done manually in MercureProcessor through ReviewRemoveProcessor
processor: ReviewRemoveProcessor::class
),
],
normalizationContext: [
IriTransformerNormalizer::CONTEXT_KEY => [
'book' => '/books/{id}{._format}',
'user' => '/users/{id}{._format}',
],
'item_uri_template' => '/books/{bookId}/reviews/{id}{._format}',
'skip_null_values' => true,
'groups' => ['Review:read'],
],
denormalizationContext: ['groups' => ['Review:write']]
Expand Down
5 changes: 4 additions & 1 deletion api/src/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
security: 'is_granted("ROLE_USER") and object.getUserIdentifier() === user.getUserIdentifier()'
),
],
normalizationContext: ['groups' => ['User:read']]
normalizationContext: [
'groups' => ['User:read'],
'skip_null_values' => true,
]
)]
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
Expand Down
19 changes: 17 additions & 2 deletions api/src/State/Processor/BookPersistProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
{
public function __construct(
#[Autowire(service: PersistProcessor::class)]
private ProcessorInterface $processor,
private ProcessorInterface $persistProcessor,
#[Autowire(service: MercureProcessor::class)]
private ProcessorInterface $mercureProcessor,
private HttpClientInterface $client,
private DecoderInterface $decoder
) {
Expand All @@ -40,7 +42,20 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
}

// save entity
$this->processor->process($data, $operation, $uriVariables, $context);
$this->persistProcessor->process($data, $operation, $uriVariables, $context);

// publish on Mercure
// todo find a way to do it in API Platform
foreach (['/admin/books/{id}{._format}', '/books/{id}{._format}'] as $uriTemplate) {
$this->mercureProcessor->process(
$data,
$operation,
$uriVariables,
$context + [
'item_uri_template' => $uriTemplate,
]
);
}

return $data;
}
Expand Down
59 changes: 59 additions & 0 deletions api/src/State/Processor/BookRemoveProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace App\State\Processor;

use ApiPlatform\Api\IriConverterInterface;
use ApiPlatform\Api\UrlGeneratorInterface;
use ApiPlatform\Doctrine\Common\State\RemoveProcessor as DoctrineRemoveProcessor;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Book;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

final readonly class BookRemoveProcessor implements ProcessorInterface
{
public function __construct(
#[Autowire(service: DoctrineRemoveProcessor::class)]
private ProcessorInterface $removeProcessor,
#[Autowire(service: MercureProcessor::class)]
private ProcessorInterface $mercureProcessor,
private ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory,
private IriConverterInterface $iriConverter
) {
}

/**
* @param Book $data
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): Book
{
$object = clone $data;

// remove entity
$this->removeProcessor->process($data, $operation, $uriVariables, $context);

// publish on Mercure
// todo find a way to do it in API Platform
foreach (['/admin/books/{id}{._format}', '/books/{id}{._format}'] as $uriTemplate) {
$iri = $this->iriConverter->getIriFromResource(
$object,
UrlGeneratorInterface::ABS_URL,
$this->resourceMetadataCollectionFactory->create(Book::class)->getOperation($uriTemplate)
);
$this->mercureProcessor->process(
$object,
$operation,
$uriVariables,
$context + [
'item_uri_template' => $uriTemplate,
'data' => json_encode(['@id' => $iri]),
]
);
}

return $data;
}
}
Loading

0 comments on commit f062fe7

Please sign in to comment.