Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/State/Processor/AddLinkHeaderProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\WebLink\HttpHeaderSerializer;

Expand All @@ -24,8 +26,10 @@
*
* @implements ProcessorInterface<T1, T2>
*/
final class AddLinkHeaderProcessor implements ProcessorInterface
final class AddLinkHeaderProcessor implements ProcessorInterface, StopwatchAwareInterface
{
use StopwatchAwareTrait;

/**
* @param ProcessorInterface<T1, T2> $decorated
*/
Expand All @@ -44,11 +48,13 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
return $response;
}

$this->stopwatch?->start('api_platform.processor.add_link_header');
// We add our header here as Symfony does it only for the main Request and we want it to be done on errors (sub-request) as well
$linksProvider = $request->attributes->get('_api_platform_links');
if ($this->serializer && ($links = $linksProvider?->getLinks())) {
$response->headers->set('Link', $this->serializer->serialize($links));
}
$this->stopwatch?->stop('api_platform.processor.add_link_header');

return $response;
}
Expand Down
9 changes: 8 additions & 1 deletion src/State/Processor/RespondProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use ApiPlatform\Metadata\Util\ClassInfoTrait;
use ApiPlatform\Metadata\Util\CloneTrait;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface as SymfonyHttpExceptionInterface;

Expand All @@ -35,10 +37,11 @@
*
* @author Kévin Dunglas <[email protected]>
*/
final class RespondProcessor implements ProcessorInterface
final class RespondProcessor implements ProcessorInterface, StopwatchAwareInterface
{
use ClassInfoTrait;
use CloneTrait;
use StopwatchAwareTrait;

public const METHOD_TO_CODE = [
'POST' => Response::HTTP_CREATED,
Expand All @@ -62,6 +65,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
return $data;
}

$this->stopwatch?->start('api_platform.processor.respond');

$headers = [
'Content-Type' => \sprintf('%s; charset=utf-8', $request->getMimeType($request->getRequestFormat())),
'Vary' => 'Accept',
Expand Down Expand Up @@ -144,6 +149,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
}
}

$this->stopwatch?->stop('api_platform.processor.respond');

return new Response(
$data,
$status,
Expand Down
12 changes: 11 additions & 1 deletion src/State/Processor/SerializeProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ResourceList;
use ApiPlatform\State\SerializerContextBuilderInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
Expand All @@ -33,8 +35,10 @@
*
* @author Kévin Dunglas <[email protected]>
*/
final class SerializeProcessor implements ProcessorInterface
final class SerializeProcessor implements ProcessorInterface, StopwatchAwareInterface
{
use StopwatchAwareTrait;

/**
* @param ProcessorInterface<mixed, mixed>|null $processor
*/
Expand All @@ -48,6 +52,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
return $this->processor ? $this->processor->process($data, $operation, $uriVariables, $context) : $data;
}

$this->stopwatch?->start('api_platform.processor.serialize');

// @see ApiPlatform\State\Processor\RespondProcessor
$context['original_data'] = $data;

Expand All @@ -60,6 +66,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
$serializerContext['uri_variables'] = $uriVariables;

if (isset($serializerContext['output']) && \array_key_exists('class', $serializerContext['output']) && null === $serializerContext['output']['class']) {
$this->stopwatch?->stop('api_platform.processor.serialize');

return $this->processor ? $this->processor->process(null, $operation, $uriVariables, $context) : null;
}

Expand All @@ -81,6 +89,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
$request->attributes->set('_api_platform_links', $linkProvider);
}

$this->stopwatch?->stop('api_platform.processor.serialize');

return $this->processor ? $this->processor->process($serialized, $operation, $uriVariables, $context) : $serialized;
}
}
7 changes: 6 additions & 1 deletion src/State/Processor/WriteProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Util\ClassInfoTrait;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use Symfony\Component\HttpFoundation\Response;

/**
Expand All @@ -29,9 +31,10 @@
* @author Kévin Dunglas <[email protected]>
* @author Baptiste Meyer <[email protected]>
*/
final class WriteProcessor implements ProcessorInterface
final class WriteProcessor implements ProcessorInterface, StopwatchAwareInterface
{
use ClassInfoTrait;
use StopwatchAwareTrait;

/**
* @param ProcessorInterface<mixed, mixed> $processor
Expand All @@ -51,7 +54,9 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
return $this->processor ? $this->processor->process($data, $operation, $uriVariables, $context) : $data;
}

$this->stopwatch?->start('api_platform.processor.write');
$data = $this->callableProcessor->process($data, $operation, $uriVariables, $context);
$this->stopwatch?->stop('api_platform.processor.write');

return $this->processor ? $this->processor->process($data, $operation, $uriVariables, $context) : $data;
}
Expand Down
7 changes: 6 additions & 1 deletion src/State/Provider/ContentNegotiationProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Util\ContentNegotiationTrait;
use ApiPlatform\State\ProviderInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use Negotiation\Negotiator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;

final class ContentNegotiationProvider implements ProviderInterface
final class ContentNegotiationProvider implements ProviderInterface, StopwatchAwareInterface
{
use ContentNegotiationTrait;
use StopwatchAwareTrait;

/**
* @param array<string, string[]> $formats
Expand All @@ -41,12 +44,14 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
return $this->decorated?->provide($operation, $uriVariables, $context);
}

$this->stopwatch?->start('api_platform.provider.content_negotiation');
$isErrorOperation = $operation instanceof ErrorOperation;

$formats = $operation->getOutputFormats() ?? ($isErrorOperation ? $this->errorFormats : $this->formats);
$this->addRequestFormats($request, $formats);
$request->attributes->set('input_format', $this->getInputFormat($operation, $request));
$request->setRequestFormat($this->getRequestFormat($request, $formats, !$isErrorOperation));
$this->stopwatch?->stop('api_platform.provider.content_negotiation');

return $this->decorated?->provide($operation, $uriVariables, $context);
}
Expand Down
12 changes: 10 additions & 2 deletions src/State/Provider/DeserializeProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use ApiPlatform\State\SerializerContextBuilderInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use ApiPlatform\Validator\Exception\ValidationException;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
Expand All @@ -30,8 +32,10 @@
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;

final class DeserializeProvider implements ProviderInterface
final class DeserializeProvider implements ProviderInterface, StopwatchAwareInterface
{
use StopwatchAwareTrait;

public function __construct(
private readonly ?ProviderInterface $decorated,
private readonly SerializerInterface $serializer,
Expand Down Expand Up @@ -59,6 +63,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
return $data;
}

$this->stopwatch?->start('api_platform.provider.deserialize');

$contentType = $request->headers->get('CONTENT_TYPE');
if (null === $contentType || '' === $contentType) {
throw new UnsupportedMediaTypeHttpException('The "Content-Type" header must exist.');
Expand Down Expand Up @@ -94,7 +100,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
unset($serializerContext[SerializerContextBuilderInterface::ASSIGN_OBJECT_TO_POPULATE]);

try {
return $this->serializer->deserialize((string) $request->getContent(), $serializerContext['deserializer_type'] ?? $operation->getClass(), $format, $serializerContext);
$data = $this->serializer->deserialize((string) $request->getContent(), $serializerContext['deserializer_type'] ?? $operation->getClass(), $format, $serializerContext);
} catch (PartialDenormalizationException $e) {
if (!class_exists(ConstraintViolationList::class)) {
throw $e;
Expand All @@ -118,6 +124,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
}
}

$this->stopwatch?->stop('api_platform.provider.deserialize');

return $data;
}

Expand Down
7 changes: 6 additions & 1 deletion src/State/Provider/ParameterProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
use ApiPlatform\State\ParameterNotFound;
use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider;
use ApiPlatform\State\ProviderInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use ApiPlatform\State\Util\ParameterParserTrait;
use ApiPlatform\State\Util\RequestParser;
use Psr\Container\ContainerInterface;
Expand All @@ -32,16 +34,18 @@
*
* @experimental
*/
final class ParameterProvider implements ProviderInterface
final class ParameterProvider implements ProviderInterface, StopwatchAwareInterface
{
use ParameterParserTrait;
use StopwatchAwareTrait;

public function __construct(private readonly ?ProviderInterface $decorated = null, private readonly ?ContainerInterface $locator = null)
{
}

public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$this->stopwatch?->start('api_platform.provider.parameter');
$request = $context['request'] ?? null;
if ($request && null === $request->attributes->get('_api_query_parameters')) {
$queryString = RequestParser::getQueryString($request);
Expand Down Expand Up @@ -95,6 +99,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c

$request?->attributes->set('_api_operation', $operation);
$context['operation'] = $operation;
$this->stopwatch?->stop('api_platform.provider.parameter');

return $this->decorated?->provide($operation, $uriVariables, $context);
}
Expand Down
9 changes: 8 additions & 1 deletion src/State/Provider/ReadProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use ApiPlatform\State\Exception\ProviderNotFoundException;
use ApiPlatform\State\ProviderInterface;
use ApiPlatform\State\SerializerContextBuilderInterface;
use ApiPlatform\State\StopwatchAwareInterface;
use ApiPlatform\State\StopwatchAwareTrait;
use ApiPlatform\State\UriVariablesResolverTrait;
use ApiPlatform\State\Util\OperationRequestInitiatorTrait;
use ApiPlatform\State\Util\RequestParser;
Expand All @@ -31,10 +33,11 @@
*
* @author Kévin Dunglas <[email protected]>
*/
final class ReadProvider implements ProviderInterface
final class ReadProvider implements ProviderInterface, StopwatchAwareInterface
{
use CloneTrait;
use OperationRequestInitiatorTrait;
use StopwatchAwareTrait;
use UriVariablesResolverTrait;

public function __construct(
Expand All @@ -55,6 +58,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
return null;
}

$this->stopwatch?->start('api_platform.provider.read');

if (null === ($filters = $request?->attributes->get('_api_filters')) && $request) {
$queryString = RequestParser::getQueryString($request);
$filters = $queryString ? RequestParser::parseRequestParams($queryString) : null;
Expand Down Expand Up @@ -96,6 +101,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
$request?->attributes->set('data', $data);
$request?->attributes->set('previous_data', $this->clone($data));

$this->stopwatch?->stop('api_platform.provider.read');

return $data;
}
}
31 changes: 31 additions & 0 deletions src/State/StopwatchAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\State;

use Symfony\Component\Stopwatch\Stopwatch;

/**
* Interface for classes that can be injected with a Stopwatch instance.
*
* @internal
*
* @author Kévin Dunglas <[email protected]>
*/
interface StopwatchAwareInterface
{
/**
* Sets the Stopwatch instance.
*/
public function setStopwatch(Stopwatch $stopwatch): void;
}
29 changes: 29 additions & 0 deletions src/State/StopwatchAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\State;

use Symfony\Component\Stopwatch\Stopwatch;

/**
* @internal
*/
trait StopwatchAwareTrait
{
private ?Stopwatch $stopwatch = null;

public function setStopwatch(Stopwatch $stopwatch): void
{
$this->stopwatch = $stopwatch;
}
}
Loading
Loading