Skip to content

Commit

Permalink
fix: better generics support for State\ProcessorInterface (#6103)
Browse files Browse the repository at this point in the history
* fix: better generics support for State\ProcessorInterface
  • Loading branch information
dunglas committed Jan 15, 2024
1 parent 227c858 commit 1c1023a
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 16 deletions.
8 changes: 7 additions & 1 deletion src/HttpCache/State/AddHeadersProcessor.php
Expand Up @@ -18,10 +18,16 @@
use ApiPlatform\State\ProcessorInterface;
use Symfony\Component\HttpFoundation\Response;

/**
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*/
final class AddHeadersProcessor implements ProcessorInterface
{
/**
* @param ProcessorInterface<Response>|ProcessorInterface<mixed> $decorated
* @param ProcessorInterface<T1, T2> $decorated
*/
public function __construct(private readonly ProcessorInterface $decorated, private readonly bool $etag = false, private readonly ?int $maxAge = null, private readonly ?int $sharedMaxAge = null, private readonly ?array $vary = null, private readonly ?bool $public = null, private readonly ?int $staleWhileRevalidate = null, private readonly ?int $staleIfError = null)
{
Expand Down
8 changes: 7 additions & 1 deletion src/Hydra/State/HydraLinkProcessor.php
Expand Up @@ -22,12 +22,18 @@
use Symfony\Component\WebLink\GenericLinkProvider;
use Symfony\Component\WebLink\Link;

/**
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*/
final class HydraLinkProcessor implements ProcessorInterface
{
use CorsTrait;

/**
* @param ProcessorInterface<mixed> $decorated
* @param ProcessorInterface<T1, T2> $decorated
*/
public function __construct(private readonly ProcessorInterface $decorated, private readonly UrlGeneratorInterface $urlGenerator)
{
Expand Down
8 changes: 7 additions & 1 deletion src/State/CallableProcessor.php
Expand Up @@ -17,6 +17,12 @@
use ApiPlatform\Metadata\Operation;
use Psr\Container\ContainerInterface;

/**
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*/
final class CallableProcessor implements ProcessorInterface
{
public function __construct(private readonly ?ContainerInterface $locator = null)
Expand All @@ -40,7 +46,7 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
throw new RuntimeException(sprintf('Processor "%s" not found on operation "%s"', $processor, $operation->getName()));
}

/** @var ProcessorInterface $processorInstance */
/** @var ProcessorInterface<T1, T2> $processorInstance */
$processorInstance = $this->locator->get($processor);

return $processorInstance->process($data, $operation, $uriVariables, $context);
Expand Down
9 changes: 9 additions & 0 deletions src/State/Processor/AddLinkHeaderProcessor.php
Expand Up @@ -18,8 +18,17 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\WebLink\HttpHeaderSerializer;

/**
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*/
final class AddLinkHeaderProcessor implements ProcessorInterface
{
/**
* @param ProcessorInterface<T1, T2> $decorated
*/
public function __construct(private readonly ProcessorInterface $decorated, private readonly ?HttpHeaderSerializer $serializer = new HttpHeaderSerializer())
{
}
Expand Down
2 changes: 1 addition & 1 deletion src/State/Processor/RespondProcessor.php
Expand Up @@ -74,7 +74,7 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
$status = $operation->getStatus();

if ($sunset = $operation->getSunset()) {
$headers['Sunset'] = (new \DateTimeImmutable($sunset))->format(\DateTime::RFC1123);
$headers['Sunset'] = (new \DateTimeImmutable($sunset))->format(\DateTimeInterface::RFC1123);
}

if ($acceptPatch = $operation->getAcceptPatch()) {
Expand Down
8 changes: 8 additions & 0 deletions src/State/Processor/SerializeProcessor.php
Expand Up @@ -26,10 +26,18 @@
/**
* Serializes data.
*
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
final class SerializeProcessor implements ProcessorInterface
{
/**
* @param ProcessorInterface<T1, T2> $processor
*/
public function __construct(private readonly ProcessorInterface $processor, private readonly SerializerInterface $serializer, private readonly SerializerContextBuilderInterface $serializerContextBuilder)
{
}
Expand Down
9 changes: 9 additions & 0 deletions src/State/Processor/WriteProcessor.php
Expand Up @@ -21,13 +21,22 @@
/**
* Bridges persistence and the API system.
*
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*
* @author Kévin Dunglas <dunglas@gmail.com>
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
*/
final class WriteProcessor implements ProcessorInterface
{
use ClassInfoTrait;

/**
* @param ProcessorInterface<T1, T2> $processor
* @param ProcessorInterface<T1, T2> $callableProcessor
*/
public function __construct(private readonly ProcessorInterface $processor, private readonly ProcessorInterface $callableProcessor)
{
}
Expand Down
15 changes: 9 additions & 6 deletions src/State/ProcessorInterface.php
Expand Up @@ -14,23 +14,26 @@
namespace ApiPlatform\State;

use ApiPlatform\Metadata\Operation;
use Symfony\Component\HttpFoundation\Request;

/**
* Process data: send an email, persist to storage, add to queue etc.
* Processes data: sends an email, persists to storage, adds to queue etc.
*
* @template T
* @template T1
* @template T2
*
* @author Antoine Bluchet <soyuka@gmail.com>
*/
interface ProcessorInterface
{
/**
* Handle the state.
* Handles the state.
*
* @param array<string, mixed> $uriVariables
* @param array<string, mixed>&array{request?: \Symfony\Component\HttpFoundation\Request, previous_data?: mixed, resource_class?: string, original_data?: mixed} $context
* @param T1 $data
* @param array<string, mixed> $uriVariables
* @param array<string, mixed>&array{request?: Request, previous_data?: mixed, resource_class?: string, original_data?: mixed} $context
*
* @return T
* @return T2
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []);

This comment has been minimized.

Copy link
@manuelmeister

manuelmeister Jan 20, 2024

@dunglas Why is $data still mixed? Wouldn't it make sense to remove the type, as it is specified in the @template T1?

}
8 changes: 5 additions & 3 deletions src/State/ProviderInterface.php
Expand Up @@ -14,6 +14,8 @@
namespace ApiPlatform\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\Pagination\PartialPaginatorInterface;
use Symfony\Component\HttpFoundation\Request;

/**
* Retrieves data from a persistence layer.
Expand All @@ -27,10 +29,10 @@ interface ProviderInterface
/**
* Provides data.
*
* @param array<string, mixed> $uriVariables
* @param array<string, mixed>|array{request?: \Symfony\Component\HttpFoundation\Request, resource_class?: string} $context
* @param array<string, mixed> $uriVariables
* @param array<string, mixed>|array{request?: Request, resource_class?: string} $context
*
* @return T|Pagination\PartialPaginatorInterface<T>|iterable<T>|null
* @return T|PartialPaginatorInterface<T>|iterable<T>|null
*/
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null;
}
8 changes: 7 additions & 1 deletion src/Symfony/State/MercureLinkProcessor.php
Expand Up @@ -17,10 +17,16 @@
use ApiPlatform\State\ProcessorInterface;
use Symfony\Component\Mercure\Discovery;

/**
* @template T1
* @template T2
*
* @implements ProcessorInterface<T1, T2>
*/
final class MercureLinkProcessor implements ProcessorInterface
{
/**
* @param ProcessorInterface<mixed> $decorated
* @param ProcessorInterface<T1, T2> $decorated
*/
public function __construct(private readonly ProcessorInterface $decorated, private readonly Discovery $discovery)
{
Expand Down
4 changes: 2 additions & 2 deletions tests/State/RespondProcessorTest.php
Expand Up @@ -71,7 +71,7 @@ public function testRedirectToOperation(): void
return ($args[2] ?? null)?->getUriTemplate() ?? '/default';
});

/** @var ProcessorInterface<Response> $respondProcessor */
/** @var ProcessorInterface<string, Response> $respondProcessor */
$respondProcessor = new RespondProcessor($iriConverter->reveal(), $resourceClassResolver->reveal(), $operationMetadataFactory->reveal());

$response = $respondProcessor->process('content', $canonicalUriTemplateRedirectingOperation, context: [
Expand Down Expand Up @@ -103,7 +103,7 @@ public function testAddsExceptionHeaders(): void
{
$operation = new Get();

/** @var ProcessorInterface<Response> $respondProcessor */
/** @var ProcessorInterface<string, Response> $respondProcessor */
$respondProcessor = new RespondProcessor();
$req = new Request();
$req->attributes->set('exception', new TooManyRequestsHttpException(32));
Expand Down

0 comments on commit 1c1023a

Please sign in to comment.