diff --git a/composer.json b/composer.json index 4c36ec7d..35e9f9d3 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,7 @@ "symfony/form": "6.4.*", "symfony/framework-bundle": "6.4.*", "symfony/http-client": "6.4.*", + "symfony/http-client-contracts": "^3.5", "symfony/intl": "6.4.*", "symfony/lock": "6.4.*", "symfony/mailer": "6.4.*", diff --git a/config/services.yaml b/config/services.yaml index 7feb7953..a5ee4243 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -519,6 +519,7 @@ services: # RZ\Roadiz\CoreBundle\Document\MediaFinder\UnsplashPictureFinder: arguments: + - '@http_client' - '%roadiz_core.medias.unsplash_client_id%' RZ\Roadiz\Documents\MediaFinders\RandomImageFinder: alias: RZ\Roadiz\CoreBundle\Document\MediaFinder\UnsplashPictureFinder @@ -641,6 +642,7 @@ services: RZ\Roadiz\Documents\MediaFinders\EmbedFinderFactory: arguments: + - '@http_client' - '%roadiz_core.medias.supported_platforms%' RZ\Roadiz\Documents\Renderer\ChainRenderer: diff --git a/src/DependencyInjection/RoadizCoreExtension.php b/src/DependencyInjection/RoadizCoreExtension.php index 71959864..de82ceec 100644 --- a/src/DependencyInjection/RoadizCoreExtension.php +++ b/src/DependencyInjection/RoadizCoreExtension.php @@ -19,9 +19,9 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Repository\NodesSourcesRepository; -use RZ\Roadiz\CoreBundle\Webhook\Message\GenericJsonPostMessage; -use RZ\Roadiz\CoreBundle\Webhook\Message\GitlabPipelineTriggerMessage; -use RZ\Roadiz\CoreBundle\Webhook\Message\NetlifyBuildHookMessage; +use RZ\Roadiz\CoreBundle\Webhook\Message\GenericJsonPostMessageInterface; +use RZ\Roadiz\CoreBundle\Webhook\Message\GitlabPipelineTriggerMessageInterface; +use RZ\Roadiz\CoreBundle\Webhook\Message\NetlifyBuildHookMessageInterface; use RZ\Roadiz\Markdown\CommonMark; use RZ\Roadiz\Markdown\MarkdownInterface; use Solarium\Core\Client\Adapter\Curl; @@ -113,9 +113,9 @@ public function load(array $configs, ContainerBuilder $container): void $container->setParameter('roadiz_core.medias.supported_platforms', []); $container->setParameter('roadiz_core.webhook.message_types', [ - 'webhook.type.generic_json_post' => GenericJsonPostMessage::class, - 'webhook.type.gitlab_pipeline' => GitlabPipelineTriggerMessage::class, - 'webhook.type.netlify_build_hook' => NetlifyBuildHookMessage::class, + 'webhook.type.generic_json_post' => GenericJsonPostMessageInterface::class, + 'webhook.type.gitlab_pipeline' => GitlabPipelineTriggerMessageInterface::class, + 'webhook.type.netlify_build_hook' => NetlifyBuildHookMessageInterface::class, ]); $this->registerEntityGenerator($config, $container); diff --git a/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php b/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php index 7b1dcb55..80d085fa 100644 --- a/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php +++ b/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php @@ -39,9 +39,6 @@ public function __construct( ) { } - /** - * @throws \GuzzleHttp\Exception\GuzzleException - */ public function preUpdate(PreUpdateEventArgs $event): void { $user = $event->getObject(); diff --git a/src/Document/MediaFinder/EmbedFinderTrait.php b/src/Document/MediaFinder/EmbedFinderTrait.php index bd5b5787..07d2e011 100644 --- a/src/Document/MediaFinder/EmbedFinderTrait.php +++ b/src/Document/MediaFinder/EmbedFinderTrait.php @@ -5,12 +5,12 @@ namespace RZ\Roadiz\CoreBundle\Document\MediaFinder; use Doctrine\Persistence\ObjectManager; -use GuzzleHttp\Exception\ClientException; use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\Documents\Exceptions\APINeedsAuthentificationException; use RZ\Roadiz\Documents\Models\DocumentInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; trait EmbedFinderTrait { @@ -50,8 +50,8 @@ protected function injectMetaInDocument(ObjectManager $objectManager, DocumentIn } } } catch (APINeedsAuthentificationException $exception) { - // do no prevent from creating document if credentials are not provided. - } catch (ClientException $exception) { + // do not prevent from creating document if credentials are not provided. + } catch (ClientExceptionInterface $exception) { // do not prevent from creating document if platform has errors, such as // too much API usage. } diff --git a/src/Document/MediaFinder/PodcastFinder.php b/src/Document/MediaFinder/PodcastFinder.php index 95090585..384373bb 100644 --- a/src/Document/MediaFinder/PodcastFinder.php +++ b/src/Document/MediaFinder/PodcastFinder.php @@ -5,11 +5,11 @@ namespace RZ\Roadiz\CoreBundle\Document\MediaFinder; use Doctrine\Persistence\ObjectManager; -use GuzzleHttp\Exception\ClientException; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\Documents\MediaFinders\AbstractPodcastFinder; use RZ\Roadiz\Documents\Models\DocumentInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; class PodcastFinder extends AbstractPodcastFinder { @@ -33,8 +33,8 @@ protected function injectMetaFromPodcastItem( $documentTr->setCopyright($this->getPodcastItemCopyright($item)); $objectManager->persist($documentTr); } - } catch (ClientException $exception) { - // do no prevent from creating document if platform has errors, such as + } catch (ClientExceptionInterface $exception) { + // do not prevent from creating document if platform has errors, such as // too much API usage. } } diff --git a/src/EventSubscriber/CloudflareCacheEventSubscriber.php b/src/EventSubscriber/CloudflareCacheEventSubscriber.php index be4f1da7..4e2a9f76 100644 --- a/src/EventSubscriber/CloudflareCacheEventSubscriber.php +++ b/src/EventSubscriber/CloudflareCacheEventSubscriber.php @@ -4,31 +4,29 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ConnectException; -use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Psr7\Request; -use Psr\Http\Message\RequestInterface; use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Cache\CloudflareProxyCache; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Event\Cache\CachePurgeRequestEvent; use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\ExceptionInterface; +use Symfony\Component\Messenger\Exception\ExceptionInterface as MessengerExceptionInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; -final class CloudflareCacheEventSubscriber implements EventSubscriberInterface +final readonly class CloudflareCacheEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly MessageBusInterface $bus, - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly UrlGeneratorInterface $urlGenerator, - private readonly LoggerInterface $logger, + private MessageBusInterface $bus, + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private UrlGeneratorInterface $urlGenerator, + private LoggerInterface $logger, ) { } @@ -58,22 +56,14 @@ public function onBanRequest(CachePurgeRequestEvent $event): void self::class, 'Cloudflare proxy cache' ); - } catch (RequestException $e) { - if (null !== $e->getResponse()) { - $data = \json_decode($e->getResponse()->getBody()->getContents(), true); - $event->addError( - $data['errors'][0]['message'] ?? $e->getMessage(), - self::class, - 'Cloudflare proxy cache' - ); - } else { - $event->addError( - $e->getMessage(), - self::class, - 'Cloudflare proxy cache' - ); - } - } catch (ConnectException $e) { + } catch (HttpExceptionInterface $e) { + $data = \json_decode($e->getResponse()->getContent(false), true); + $event->addError( + $data['errors'][0]['message'] ?? $e->getMessage(), + self::class, + 'Cloudflare proxy cache' + ); + } catch (ExceptionInterface $e) { $event->addError( $e->getMessage(), self::class, @@ -105,7 +95,7 @@ public function onPurgeRequest(NodesSourcesUpdatedEvent $event): void UrlGeneratorInterface::ABSOLUTE_URL )]); $this->sendRequest($purgeRequest); - } catch (ClientException $e) { + } catch (ExceptionInterface $e) { // do nothing } } @@ -123,7 +113,7 @@ private function getCloudflareCacheProxy(): CloudflareProxyCache /** * @throws \JsonException */ - protected function createRequest(array $body): Request + protected function createRequest(array $body): HttpRequestMessageInterface { $headers = [ 'Content-type' => 'application/json', @@ -139,18 +129,21 @@ protected function createRequest(array $body): Request ); $body = \json_encode($body, JSON_THROW_ON_ERROR); - return new Request( + return new HttpRequestMessage( 'POST', $uri, - $headers, - $body + [ + 'timeout' => $this->getCloudflareCacheProxy()->getTimeout(), + 'headers' => $headers, + 'body' => $body, + ], ); } /** * @throws \JsonException */ - protected function createBanRequest(): Request + protected function createBanRequest(): HttpRequestMessageInterface { return $this->createRequest([ 'purge_everything' => true, @@ -162,21 +155,18 @@ protected function createBanRequest(): Request * * @throws \JsonException */ - protected function createPurgeRequest(array $uris = []): Request + protected function createPurgeRequest(array $uris = []): HttpRequestMessageInterface { return $this->createRequest([ 'files' => $uris, ]); } - protected function sendRequest(RequestInterface $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => $this->getCloudflareCacheProxy()->getTimeout(), - ]))); - } catch (ExceptionInterface $exception) { + $this->bus->dispatch(new Envelope($requestMessage)); + } catch (MessengerExceptionInterface $exception) { $this->logger->error($exception->getMessage()); } } diff --git a/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php b/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php index 270a423e..2fb5327c 100644 --- a/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php +++ b/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php @@ -4,14 +4,14 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use GuzzleHttp\Psr7\Request; use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Event\Cache\CachePurgeRequestEvent; use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Message\PurgeReverseProxyCacheMessage; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; @@ -19,12 +19,12 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Workflow\Event\Event; -final class ReverseProxyCacheEventSubscriber implements EventSubscriberInterface +final readonly class ReverseProxyCacheEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly MessageBusInterface $bus, - private readonly LoggerInterface $logger, + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private MessageBusInterface $bus, + private LoggerInterface $logger, ) { } @@ -81,7 +81,7 @@ public function onPurgeRequest(NodesSourcesUpdatedEvent $event): void } /** - * @return Request[] + * @return HttpRequestMessageInterface[] */ protected function createBanRequests(): array { @@ -94,11 +94,14 @@ protected function createBanRequests(): array } else { $uri = $frontend->getHost(); } - $requests[$frontend->getName()] = new Request( + $requests[$frontend->getName()] = new HttpRequestMessage( 'BAN', $uri, [ - 'Host' => $frontend->getDomainName(), + 'timeout' => 3, + 'headers' => [ + 'Host' => $frontend->getDomainName(), + ], ] ); } @@ -115,13 +118,10 @@ protected function purgeNodesSources(NodesSources $nodeSource): void } } - protected function sendRequest(Request $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => 3, - ]))); + $this->bus->dispatch(new Envelope($requestMessage)); } catch (ExceptionInterface $exception) { $this->logger->error($exception->getMessage()); } diff --git a/src/Form/Constraint/RecaptchaValidator.php b/src/Form/Constraint/RecaptchaValidator.php index f6ab3d4c..8b55ec86 100644 --- a/src/Form/Constraint/RecaptchaValidator.php +++ b/src/Form/Constraint/RecaptchaValidator.php @@ -4,28 +4,28 @@ namespace RZ\Roadiz\CoreBundle\Form\Constraint; -use GuzzleHttp\Client; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @see https://github.com/thrace-project/form-bundle/blob/master/Validator/Constraint/RecaptchaValidator.php */ class RecaptchaValidator extends ConstraintValidator implements RecaptchaServiceInterface { - protected RequestStack $requestStack; - protected ?string $recaptchaPrivateKey; - - public function __construct(RequestStack $requestStack, ?string $recaptchaPrivateKey) - { - $this->requestStack = $requestStack; - $this->recaptchaPrivateKey = $recaptchaPrivateKey; + public function __construct( + protected HttpClientInterface $client, + protected RequestStack $requestStack, + protected ?string $recaptchaPrivateKey, + ) { } /** - * @throws \GuzzleHttp\Exception\GuzzleException - * * @see \Symfony\Component\Validator\ConstraintValidator::validate() */ public function validate(mixed $data, Constraint $constraint): void @@ -71,7 +71,10 @@ public function validate(mixed $data, Constraint $constraint): void * * @return true|mixed * - * @throws \GuzzleHttp\Exception\GuzzleException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface */ public function check( string $responseValue, @@ -81,21 +84,17 @@ public function check( return true; } - $data = [ - 'secret' => $this->recaptchaPrivateKey, - 'response' => $responseValue, - ]; - - $client = new Client(); - $response = $client->post($verifyUrl, [ - 'form_params' => $data, - 'connect_timeout' => 10, + $response = $this->client->request('POST', $verifyUrl, [ + 'query' => [ + 'secret' => $this->recaptchaPrivateKey, + 'response' => $responseValue, + ], 'timeout' => 10, 'headers' => [ 'Accept' => 'application/json', ], ]); - $jsonResponse = json_decode($response->getBody()->getContents(), true); + $jsonResponse = json_decode($response->getContent(false), true); return (isset($jsonResponse['success']) && true === $jsonResponse['success']) ? (true) : diff --git a/src/Form/Constraint/ValidFacebookNameValidator.php b/src/Form/Constraint/ValidFacebookNameValidator.php index a04127b3..13d8675a 100644 --- a/src/Form/Constraint/ValidFacebookNameValidator.php +++ b/src/Form/Constraint/ValidFacebookNameValidator.php @@ -16,8 +16,6 @@ public function __construct(private readonly FacebookPictureFinder $facebookPict /** * @param ValidFacebookName $constraint - * - * @throws \GuzzleHttp\Exception\GuzzleException */ public function validate(mixed $value, Constraint $constraint): void { diff --git a/src/Message/ApplyRealmNodeInheritanceMessage.php b/src/Message/ApplyRealmNodeInheritanceMessage.php index 61c1f9b7..a9d28eed 100644 --- a/src/Message/ApplyRealmNodeInheritanceMessage.php +++ b/src/Message/ApplyRealmNodeInheritanceMessage.php @@ -4,11 +4,11 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class ApplyRealmNodeInheritanceMessage implements AsyncMessage +final readonly class ApplyRealmNodeInheritanceMessage implements AsyncMessage { public function __construct( - private readonly int|string|null $nodeId, - private readonly int|string|null $realmId, + private int|string|null $nodeId, + private int|string|null $realmId, ) { } diff --git a/src/Message/CleanRealmNodeInheritanceMessage.php b/src/Message/CleanRealmNodeInheritanceMessage.php index 58e84bb4..28b936f8 100644 --- a/src/Message/CleanRealmNodeInheritanceMessage.php +++ b/src/Message/CleanRealmNodeInheritanceMessage.php @@ -4,11 +4,11 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class CleanRealmNodeInheritanceMessage implements AsyncMessage +final readonly class CleanRealmNodeInheritanceMessage implements AsyncMessage { public function __construct( - private readonly int|string|null $nodeId, - private readonly int|string|null $realmId, + private int|string|null $nodeId, + private int|string|null $realmId, ) { } diff --git a/src/Message/DeleteNodeTypeMessage.php b/src/Message/DeleteNodeTypeMessage.php index 74850340..9e995862 100644 --- a/src/Message/DeleteNodeTypeMessage.php +++ b/src/Message/DeleteNodeTypeMessage.php @@ -4,9 +4,9 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class DeleteNodeTypeMessage implements AsyncMessage +final readonly class DeleteNodeTypeMessage implements AsyncMessage { - public function __construct(private readonly int|string|null $nodeTypeId) + public function __construct(private int|string|null $nodeTypeId) { } diff --git a/src/Message/GuzzleRequestMessage.php b/src/Message/GuzzleRequestMessage.php deleted file mode 100644 index 59de00fe..00000000 --- a/src/Message/GuzzleRequestMessage.php +++ /dev/null @@ -1,32 +0,0 @@ -options = array_merge([ - 'debug' => false, - 'timeout' => 3, - ], $options); - } - - public function getRequest(): RequestInterface - { - return $this->request; - } - - public function getOptions(): array - { - return $this->options; - } -} diff --git a/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php index a028d088..18ef9df5 100644 --- a/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php @@ -15,11 +15,11 @@ use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; #[AsMessageHandler] -final class ApplyRealmNodeInheritanceMessageHandler +final readonly class ApplyRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly NodeOffspringResolverInterface $nodeOffspringResolver, + private ManagerRegistry $managerRegistry, + private NodeOffspringResolverInterface $nodeOffspringResolver, ) { } diff --git a/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php index ab327a2b..5ed0caec 100644 --- a/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php @@ -14,11 +14,11 @@ use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; #[AsMessageHandler] -final class CleanRealmNodeInheritanceMessageHandler +final readonly class CleanRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly NodeOffspringResolverInterface $nodeOffspringResolver, + private ManagerRegistry $managerRegistry, + private NodeOffspringResolverInterface $nodeOffspringResolver, ) { } diff --git a/src/Message/Handler/DeleteNodeTypeMessageHandler.php b/src/Message/Handler/DeleteNodeTypeMessageHandler.php index 5b396cbf..e8ff96f0 100644 --- a/src/Message/Handler/DeleteNodeTypeMessageHandler.php +++ b/src/Message/Handler/DeleteNodeTypeMessageHandler.php @@ -18,12 +18,12 @@ use Symfony\Component\Messenger\MessageBusInterface; #[AsMessageHandler] -final class DeleteNodeTypeMessageHandler +final readonly class DeleteNodeTypeMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $messageBus, + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $messageBus, ) { } diff --git a/src/Message/Handler/HttpRequestMessageHandler.php b/src/Message/Handler/HttpRequestMessageHandler.php index 6f309792..e0d349bf 100644 --- a/src/Message/Handler/HttpRequestMessageHandler.php +++ b/src/Message/Handler/HttpRequestMessageHandler.php @@ -4,32 +4,37 @@ namespace RZ\Roadiz\CoreBundle\Message\Handler; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\GuzzleException; use Psr\Log\LoggerInterface; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; #[AsMessageHandler] -final class HttpRequestMessageHandler +final readonly class HttpRequestMessageHandler { public function __construct( - private readonly LoggerInterface $logger, + private HttpClientInterface $client, + private LoggerInterface $logger, ) { } - public function __invoke(HttpRequestMessage $message): void + public function __invoke(HttpRequestMessageInterface $message): void { try { $this->logger->debug(sprintf( 'HTTP request executed: %s %s', - $message->getRequest()->getMethod(), - $message->getRequest()->getUri() + $message->getMethod(), + $message->getUri() )); - $client = new Client(); - $client->send($message->getRequest(), $message->getOptions()); - } catch (GuzzleException $exception) { + $response = $this->client->request( + $message->getMethod(), + $message->getUri(), + $message->getOptions(), + ); + $response->getStatusCode(); + } catch (ClientExceptionInterface $exception) { throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); } } diff --git a/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php b/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php index 56a2840a..33013681 100644 --- a/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php +++ b/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php @@ -7,7 +7,8 @@ use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Entity\NodesSources; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Message\PurgeReverseProxyCacheMessage; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -19,13 +20,13 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; #[AsMessageHandler] -final class PurgeReverseProxyCacheMessageHandler +final readonly class PurgeReverseProxyCacheMessageHandler { public function __construct( - private readonly MessageBusInterface $bus, - private readonly UrlGeneratorInterface $urlGenerator, - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly ManagerRegistry $managerRegistry, + private MessageBusInterface $bus, + private UrlGeneratorInterface $urlGenerator, + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private ManagerRegistry $managerRegistry, ) { } @@ -57,17 +58,22 @@ public function __invoke(PurgeReverseProxyCacheMessage $message): void } /** - * @return \GuzzleHttp\Psr7\Request[] + * @return HttpRequestMessageInterface[] */ protected function createPurgeRequests(string $path = '/'): array { $requests = []; foreach ($this->reverseProxyCacheLocator->getFrontends() as $frontend) { - $requests[$frontend->getName()] = new \GuzzleHttp\Psr7\Request( + $host = $frontend->getHost(); + str_starts_with($host, 'http') || $host = 'http://'.$host; + $requests[$frontend->getName()] = new HttpRequestMessage( Request::METHOD_PURGE, - 'http://'.$frontend->getHost().$path, + $host.$path, [ - 'Host' => $frontend->getDomainName(), + 'timeout' => 3, + 'headers' => [ + 'Host' => $frontend->getDomainName(), + ], ] ); } @@ -75,13 +81,10 @@ protected function createPurgeRequests(string $path = '/'): array return $requests; } - protected function sendRequest(\GuzzleHttp\Psr7\Request $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => 3, - ]))); + $this->bus->dispatch(new Envelope($requestMessage)); } catch (NoHandlerForMessageException $exception) { throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); } diff --git a/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php index 966af980..efbe8aa1 100644 --- a/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php @@ -20,13 +20,13 @@ use Symfony\Component\Messenger\MessageBusInterface; #[AsMessageHandler] -final class SearchRealmNodeInheritanceMessageHandler +final readonly class SearchRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $bus, - private readonly LoggerInterface $logger, + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $bus, + private LoggerInterface $logger, ) { } diff --git a/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php b/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php index a84174af..15be3e82 100644 --- a/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php +++ b/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php @@ -9,9 +9,9 @@ use Symfony\Component\Messenger\Attribute\AsMessageHandler; #[AsMessageHandler] -final class UpdateDoctrineSchemaMessageHandler +final readonly class UpdateDoctrineSchemaMessageHandler { - public function __construct(private readonly SchemaUpdater $schemaUpdater) + public function __construct(private SchemaUpdater $schemaUpdater) { } diff --git a/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php b/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php index 95eb172a..6de1b105 100644 --- a/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php +++ b/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php @@ -16,12 +16,12 @@ use Symfony\Component\Messenger\MessageBusInterface; #[AsMessageHandler] -final class UpdateNodeTypeSchemaMessageHandler +final readonly class UpdateNodeTypeSchemaMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $messageBus, + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $messageBus, ) { } diff --git a/src/Message/HttpRequestMessage.php b/src/Message/HttpRequestMessage.php index 485601d4..4b28a7ae 100644 --- a/src/Message/HttpRequestMessage.php +++ b/src/Message/HttpRequestMessage.php @@ -4,11 +4,32 @@ namespace RZ\Roadiz\CoreBundle\Message; -use Psr\Http\Message\RequestInterface; - -interface HttpRequestMessage +final readonly class HttpRequestMessage implements AsyncMessage, HttpRequestMessageInterface { - public function getRequest(): RequestInterface; + private array $options; + + public function __construct( + private string $method, + private string $uri, + array $options = [], + ) { + $this->options = array_merge([ + 'timeout' => 3, + ], $options); + } + + public function getOptions(): array + { + return $this->options; + } + + public function getMethod(): string + { + return $this->method; + } - public function getOptions(): array; + public function getUri(): string + { + return $this->uri; + } } diff --git a/src/Message/HttpRequestMessageInterface.php b/src/Message/HttpRequestMessageInterface.php new file mode 100644 index 00000000..0c7d8885 --- /dev/null +++ b/src/Message/HttpRequestMessageInterface.php @@ -0,0 +1,14 @@ +uri, - [ - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - ], - json_encode($this->payload ?? [], JSON_NUMERIC_CHECK | JSON_THROW_ON_ERROR) - ); - } - public function getOptions(): array { return [ - 'debug' => false, 'timeout' => 3, + 'body' => \json_encode($this->payload ?? [], JSON_NUMERIC_CHECK | JSON_THROW_ON_ERROR), + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ], ]; } @@ -49,4 +38,14 @@ public static function fromWebhook(WebhookInterface $webhook): self { return new self($webhook->getUri(), $webhook->getPayload()); } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } } diff --git a/src/Webhook/Message/GitlabPipelineTriggerMessage.php b/src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php similarity index 63% rename from src/Webhook/Message/GitlabPipelineTriggerMessage.php rename to src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php index b9d27893..e16429fd 100644 --- a/src/Webhook/Message/GitlabPipelineTriggerMessage.php +++ b/src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php @@ -4,23 +4,21 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use GuzzleHttp\Psr7\Request; -use Psr\Http\Message\RequestInterface; use RZ\Roadiz\CoreBundle\Message\AsyncMessage; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; -final class GitlabPipelineTriggerMessage implements AsyncMessage, HttpRequestMessage, WebhookMessage +final readonly class GitlabPipelineTriggerMessageInterface implements AsyncMessage, HttpRequestMessageInterface, WebhookMessage { public function __construct( - private readonly string $uri, - private readonly string $token, - private readonly string $ref = 'main', - private readonly ?array $variables = null, + private string $uri, + private string $token, + private string $ref = 'main', + private ?array $variables = null, ) { } - public function getRequest(): RequestInterface + public function getOptions(): array { $postBody = [ 'token' => $this->token, @@ -30,22 +28,13 @@ public function getRequest(): RequestInterface $postBody['variables'] = $this->variables; } - return new Request( - 'POST', - $this->uri, - [ + return [ + 'timeout' => 3, + 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json', ], - http_build_query($postBody) - ); - } - - public function getOptions(): array - { - return [ - 'debug' => false, - 'timeout' => 3, + 'body' => http_build_query($postBody), ]; } @@ -63,4 +52,14 @@ public static function fromWebhook(WebhookInterface $webhook): self $payload['variables'] ?? [] ); } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } } diff --git a/src/Webhook/Message/NetlifyBuildHookMessage.php b/src/Webhook/Message/NetlifyBuildHookMessage.php deleted file mode 100644 index 7138dc08..00000000 --- a/src/Webhook/Message/NetlifyBuildHookMessage.php +++ /dev/null @@ -1,53 +0,0 @@ -payload) { - return new Request( - 'POST', - $this->uri, - [ - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Accept' => 'application/json', - ], - http_build_query($this->payload) - ); - } - - return new Request('POST', $this->uri); - } - - public function getOptions(): array - { - return [ - 'debug' => false, - 'timeout' => 3, - ]; - } - - /** - * @return static - */ - public static function fromWebhook(WebhookInterface $webhook): self - { - return new self($webhook->getUri(), $webhook->getPayload()); - } -} diff --git a/src/Webhook/Message/NetlifyBuildHookMessageInterface.php b/src/Webhook/Message/NetlifyBuildHookMessageInterface.php new file mode 100644 index 00000000..02b8a1fc --- /dev/null +++ b/src/Webhook/Message/NetlifyBuildHookMessageInterface.php @@ -0,0 +1,57 @@ +payload) { + return [ + 'timeout' => 3, + 'headers' => [ + 'Accept' => 'application/json', + ], + ]; + } + + return [ + 'timeout' => 3, + 'headers' => [ + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Accept' => 'application/json', + ], + 'body' => http_build_query($this->payload), + ]; + } + + /** + * @return static + */ + public static function fromWebhook(WebhookInterface $webhook): self + { + return new self($webhook->getUri(), $webhook->getPayload()); + } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } +} diff --git a/src/Webhook/Message/WebhookMessageFactory.php b/src/Webhook/Message/WebhookMessageFactory.php index 7c080174..89b1d2b0 100644 --- a/src/Webhook/Message/WebhookMessageFactory.php +++ b/src/Webhook/Message/WebhookMessageFactory.php @@ -4,12 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; final class WebhookMessageFactory implements WebhookMessageFactoryInterface { - public function createMessage(WebhookInterface $webhook): HttpRequestMessage + public function createMessage(WebhookInterface $webhook): HttpRequestMessageInterface { if (null === $webhook->getMessageType()) { throw new \LogicException('Webhook message type is null.'); diff --git a/src/Webhook/Message/WebhookMessageFactoryInterface.php b/src/Webhook/Message/WebhookMessageFactoryInterface.php index e75c6a04..be8062ec 100644 --- a/src/Webhook/Message/WebhookMessageFactoryInterface.php +++ b/src/Webhook/Message/WebhookMessageFactoryInterface.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; interface WebhookMessageFactoryInterface { - public function createMessage(WebhookInterface $webhook): HttpRequestMessage; + public function createMessage(WebhookInterface $webhook): HttpRequestMessageInterface; }