From d8ed1532d6446077042b4923f7aed5bb45962f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 10:46:59 +0100 Subject: [PATCH 01/46] Add new pre- and post- Read, Serialize and Respond events --- src/Event/PostReadEvent.php | 60 ++++++++++++++++++++++++++++++++ src/Event/PostRespondEvent.php | 25 +++++++++++++ src/Event/PostSerializeEvent.php | 35 +++++++++++++++++++ src/Event/PreReadEvent.php | 60 ++++++++++++++++++++++++++++++++ src/Event/PreRespondEvent.php | 25 +++++++++++++ src/Event/PreSerializeEvent.php | 35 +++++++++++++++++++ 6 files changed, 240 insertions(+) create mode 100644 src/Event/PostReadEvent.php create mode 100644 src/Event/PostRespondEvent.php create mode 100644 src/Event/PostSerializeEvent.php create mode 100644 src/Event/PreReadEvent.php create mode 100644 src/Event/PreRespondEvent.php create mode 100644 src/Event/PreSerializeEvent.php diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php new file mode 100644 index 00000000000..d2d8d67bf1a --- /dev/null +++ b/src/Event/PostReadEvent.php @@ -0,0 +1,60 @@ +collectionDataProvider = $collectionDataProvider; + $this->itemDataProvider = $itemDataProvider; + $this->subresourceDataProvider = $subresourceDataProvider; + $this->serializerContextBuilder = $serializerContextBuilder; + $this->identifierConverter = $identifierConverter; + } + + public function getSerializerContextBuilder(): SerializerContextBuilderInterface + { + return $this->serializerContextBuilder; + } + + public function getCollectionDataProvider(): CollectionDataProviderInterface + { + return $this->collectionDataProvider; + } + + public function getIdentifierConverter(): IdentifierConverterInterface + { + return $this->identifierConverter; + } + + public function getItemDataProvider(): ItemDataProviderInterface + { + return $this->itemDataProvider; + } + + public function getSubresourceDataProvider(): SubresourceDataProviderInterface + { + return $this->subresourceDataProvider; + } +} diff --git a/src/Event/PostRespondEvent.php b/src/Event/PostRespondEvent.php new file mode 100644 index 00000000000..eccff03b827 --- /dev/null +++ b/src/Event/PostRespondEvent.php @@ -0,0 +1,25 @@ +resourceMetadataFactory = $resourceMetadataFactory; + } + + public function getResourceMetadataFactory(): ResourceMetadataFactoryInterface + { + return $this->resourceMetadataFactory; + } +} diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php new file mode 100644 index 00000000000..efebe6620b3 --- /dev/null +++ b/src/Event/PostSerializeEvent.php @@ -0,0 +1,35 @@ +serializer = $serializer; + $this->serializerContextBuilder = $serializerContextBuilder; + } + + public function getSerializer(): SerializerInterface + { + return $this->serializer; + } + + public function getSerializerContextBuilder(): SerializerContextBuilderInterface + { + return $this->serializerContextBuilder; + } +} diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php new file mode 100644 index 00000000000..74e3d9081bc --- /dev/null +++ b/src/Event/PreReadEvent.php @@ -0,0 +1,60 @@ +collectionDataProvider = $collectionDataProvider; + $this->itemDataProvider = $itemDataProvider; + $this->subresourceDataProvider = $subresourceDataProvider; + $this->serializerContextBuilder = $serializerContextBuilder; + $this->identifierConverter = $identifierConverter; + } + + public function getSerializerContextBuilder(): SerializerContextBuilderInterface + { + return $this->serializerContextBuilder; + } + + public function getCollectionDataProvider(): CollectionDataProviderInterface + { + return $this->collectionDataProvider; + } + + public function getIdentifierConverter(): IdentifierConverterInterface + { + return $this->identifierConverter; + } + + public function getItemDataProvider(): ItemDataProviderInterface + { + return $this->itemDataProvider; + } + + public function getSubresourceDataProvider(): SubresourceDataProviderInterface + { + return $this->subresourceDataProvider; + } +} diff --git a/src/Event/PreRespondEvent.php b/src/Event/PreRespondEvent.php new file mode 100644 index 00000000000..e7c553dd9aa --- /dev/null +++ b/src/Event/PreRespondEvent.php @@ -0,0 +1,25 @@ +resourceMetadataFactory = $resourceMetadataFactory; + } + + public function getResourceMetadataFactory(): ResourceMetadataFactoryInterface + { + return $this->resourceMetadataFactory; + } +} diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php new file mode 100644 index 00000000000..bf349fae9f3 --- /dev/null +++ b/src/Event/PreSerializeEvent.php @@ -0,0 +1,35 @@ +serializer = $serializer; + $this->serializerContextBuilder = $serializerContextBuilder; + } + + public function getSerializer(): SerializerInterface + { + return $this->serializer; + } + + public function getSerializerContextBuilder(): SerializerContextBuilderInterface + { + return $this->serializerContextBuilder; + } +} From d1f18855c39bff1f617891147bc32904578b4373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 10:48:06 +0100 Subject: [PATCH 02/46] Raise events from Read, Serialize and Respond listeners --- .../Symfony/Bundle/Resources/config/api.xml | 4 ++ src/EventListener/ReadListener.php | 13 ++++- src/EventListener/RespondListener.php | 12 ++++- src/EventListener/SerializeListener.php | 50 ++++++++----------- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index 7a23930994f..bc600762079 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -149,6 +149,7 @@ + @@ -171,12 +172,15 @@ + + + diff --git a/src/EventListener/ReadListener.php b/src/EventListener/ReadListener.php index 80fb62d439f..d3af9ea0ed9 100644 --- a/src/EventListener/ReadListener.php +++ b/src/EventListener/ReadListener.php @@ -17,12 +17,15 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\OperationDataProviderTrait; use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; +use ApiPlatform\Core\Event\PostReadEvent; +use ApiPlatform\Core\Event\PreReadEvent; use ApiPlatform\Core\Exception\InvalidIdentifierException; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Identifier\IdentifierConverterInterface; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; use ApiPlatform\Core\Util\RequestParser; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -37,14 +40,17 @@ final class ReadListener use OperationDataProviderTrait; private $serializerContextBuilder; + /** @var EventDispatcherInterface */ + private $dispatcher; - public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider = null, SerializerContextBuilderInterface $serializerContextBuilder = null, IdentifierConverterInterface $identifierConverter = null) + public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider = null, SerializerContextBuilderInterface $serializerContextBuilder = null, IdentifierConverterInterface $identifierConverter = null, EventDispatcherInterface $dispatcher = null) { $this->collectionDataProvider = $collectionDataProvider; $this->itemDataProvider = $itemDataProvider; $this->subresourceDataProvider = $subresourceDataProvider; $this->serializerContextBuilder = $serializerContextBuilder; $this->identifierConverter = $identifierConverter; + $this->dispatcher = $dispatcher; } /** @@ -89,6 +95,8 @@ public function onKernelRequest(GetResponseEvent $event) try { $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes); + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($this->collectionDataProvider, $this->itemDataProvider, $this->subresourceDataProvider, $this->serializerContextBuilder, $this->identifierConverter)); + if (isset($attributes['item_operation_name'])) { $data = $this->getItemData($identifiers, $attributes, $context); } elseif (isset($attributes['subresource_operation_name'])) { @@ -99,6 +107,9 @@ public function onKernelRequest(GetResponseEvent $event) $data = $this->getSubresourceData($identifiers, $attributes, $context); } + + $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($this->collectionDataProvider, $this->itemDataProvider, $this->subresourceDataProvider, $this->serializerContextBuilder, $this->identifierConverter)); + } catch (InvalidIdentifierException $e) { throw new NotFoundHttpException('Not found, because of an invalid identifier configuration', $e); } diff --git a/src/EventListener/RespondListener.php b/src/EventListener/RespondListener.php index d78844c2b1f..adcaa7f3ad4 100644 --- a/src/EventListener/RespondListener.php +++ b/src/EventListener/RespondListener.php @@ -13,8 +13,11 @@ namespace ApiPlatform\Core\EventListener; +use ApiPlatform\Core\Event\PostRespondEvent; +use ApiPlatform\Core\Event\PreRespondEvent; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -31,10 +34,13 @@ final class RespondListener ]; private $resourceMetadataFactory; + /** @var EventDispatcherInterface */ + private $dispatcher; - public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null) + public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null, EventDispatcherInterface $dispatcher = null) { $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->dispatcher = $dispatcher; } /** @@ -75,10 +81,14 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $status = $resourceMetadata->getOperationAttribute($attributes, 'status'); } + $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($this->resourceMetadataFactory)); + $event->setResponse(new Response( $controllerResult, $status ?? self::METHOD_TO_CODE[$request->getMethod()] ?? Response::HTTP_OK, $headers )); + + $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($this->resourceMetadataFactory)); } } diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index 803c25296cc..a3e650fed38 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -13,12 +13,14 @@ namespace ApiPlatform\Core\EventListener; +use ApiPlatform\Core\Event\PostSerializeEvent; +use ApiPlatform\Core\Event\PreSerializeEvent; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Serializer\ResourceList; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; -use Fig\Link\GenericLinkProvider; -use Fig\Link\Link; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -35,10 +37,14 @@ final class SerializeListener private $serializer; private $serializerContextBuilder; - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder) + /** @var EventDispatcherInterface */ + private $dispatcher; + + public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, EventDispatcherInterface $dispatcher) { $this->serializer = $serializer; $this->serializerContextBuilder = $serializerContextBuilder; + $this->dispatcher = $dispatcher; } /** @@ -49,7 +55,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $controllerResult = $event->getControllerResult(); $request = $event->getRequest(); - if ($controllerResult instanceof Response || !$request->attributes->getBoolean('_api_respond', true)) { + if ($controllerResult instanceof Response) { return; } @@ -59,43 +65,27 @@ public function onKernelView(GetResponseForControllerResultEvent $event) return; } - $request->attributes->set('_api_respond', true); $context = $this->serializerContextBuilder->createFromRequest($request, true, $attributes); - - if (isset($context['output_class'])) { - if (false === $context['output_class']) { - // If the output class is explicitly set to false, the response must be empty - $event->setControllerResult(''); - - return; - } - - $context['resource_class'] = $context['output_class']; - } - if ($included = $request->attributes->get('_api_included')) { $context['api_included'] = $included; } $resources = new ResourceList(); $context['resources'] = &$resources; - - $resourcesToPush = new ResourceList(); - $context['resources_to_push'] = &$resourcesToPush; + if (isset($context['output_class'])) { + $context['resource_class'] = $context['output_class']; + } $request->attributes->set('_api_normalization_context', $context); + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($this->serializer, $this->serializerContextBuilder)); + $event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($this->serializer, $this->serializerContextBuilder)); + + $request->attributes->set('_api_respond', true); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + (array) $resources); - if (!\count($resourcesToPush)) { - return; - } - $linkProvider = $request->attributes->get('_links', new GenericLinkProvider()); - foreach ($resourcesToPush as $resourceToPush) { - $linkProvider = $linkProvider->withLink(new Link('preload', $resourceToPush)); - } - $request->attributes->set('_links', $linkProvider); } /** @@ -107,6 +97,10 @@ public function onKernelView(GetResponseForControllerResultEvent $event) */ private function serializeRawData(GetResponseForControllerResultEvent $event, Request $request, $controllerResult) { + if (!$request->attributes->get('_api_respond')) { + return; + } + if (\is_object($controllerResult)) { $event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $request->attributes->get('_api_normalization_context', []))); From a15c33934c11bfb35f0e4b7fa416fef2c2d86278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 11:31:17 +0100 Subject: [PATCH 03/46] =?UTF-8?q?Add=20Symfony=E2=80=99s=20event-dispatche?= =?UTF-8?q?r=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 76 +++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index b8cc1465a56..c4e92042c7d 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "name": "api-platform/core", "type": "library", - "description": "Build a fully-featured hypermedia or GraphQL API in minutes", - "keywords": ["REST", "GraphQL", "API", "JSON-LD", "Hydra", "JSONAPI", "OpenAPI", "HAL", "Swagger"], + "description": "The ultimate solution to create web APIs.", + "keywords": ["REST", "API", "JSON", "JSON-LD", "Hydra", "Swagger", "HAL"], "homepage": "https://api-platform.com", "license": "MIT", "authors": [ @@ -17,10 +17,11 @@ "doctrine/inflector": "^1.0", "psr/cache": "^1.0", "psr/container": "^1.0", - "symfony/http-foundation": "^3.4 || ^4.0", - "symfony/http-kernel": "^3.4 || ^4.0", - "symfony/property-access": "^3.4 || ^4.0", - "symfony/property-info": "^3.4 || ^4.0", + "symfony/event-dispatcher": "^4.1", + "symfony/http-foundation": "^3.1 || ^4.0", + "symfony/http-kernel": "^2.7 || ^3.0 || ^4.0", + "symfony/property-access": "^2.7 || ^3.0 || ^4.0", + "symfony/property-info": "^3.3.11 || ^4.0", "symfony/serializer": "^4.1", "symfony/web-link": "^4.1", "willdurand/negotiation": "^2.0.3" @@ -34,54 +35,46 @@ "behatch/contexts": "3.1.0", "doctrine/annotations": "^1.2", "doctrine/doctrine-bundle": "^1.8", - "doctrine/doctrine-cache-bundle": "^1.3.5", - "doctrine/mongodb-odm": "^2.0.0@beta", - "doctrine/mongodb-odm-bundle": "^4.0.0@beta", - "doctrine/orm": "^2.6.3", - "elasticsearch/elasticsearch": "^6.0", - "friendsofsymfony/user-bundle": "dev-fix-mongodb-mapping", + "doctrine/orm": "^2.5.2", + "friendsofsymfony/user-bundle": "^2.1", "guzzlehttp/guzzle": "^6.0", "justinrainbow/json-schema": "^5.0", "nelmio/api-doc-bundle": "^2.13.3", "php-mock/php-mock-phpunit": "^2.0", "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", - "phpdocumentor/type-resolver": "^0.3 || ^0.4", - "phpspec/prophecy": "^1.8", - "phpunit/phpunit": "^7.5.2", + "phpdocumentor/type-resolver": "^0.2.1 || ^0.3 || 0.4", + "phpunit/phpunit": "^6.1", "psr/log": "^1.0", "ramsey/uuid": "^3.7", "ramsey/uuid-doctrine": "^1.4", - "symfony/asset": "^3.4 || ^4.0", - "symfony/cache": "^3.4 || ^4.0", + "symfony/asset": "^3.3 || ^4.0", + "symfony/cache": "^3.3 || ^4.0", "symfony/config": "^3.4 || ^4.0", "symfony/console": "^3.4 || ^4.0", - "symfony/debug": "^3.4 || ^4.0", + "symfony/debug": "^2.8 || ^3.0 || ^4.0", "symfony/dependency-injection": "^3.4 || ^4.0", - "symfony/doctrine-bridge": "^3.4 || ^4.0", - "symfony/event-dispatcher": "^3.4 || ^4.0", - "symfony/expression-language": "^3.4 || ^4.0", - "symfony/finder": "^3.4 || ^4.0", - "symfony/form": "^3.4 || ^4.0", - "symfony/framework-bundle": "^4.2", + "symfony/doctrine-bridge": "^2.8.12 || ^3.0 || ^4.0", + "symfony/expression-language": "^2.8 || ^3.0 || ^4.0", + "symfony/finder": "^3.3 || ^4.0", + "symfony/form": "^3.3 || ^4.0", + "symfony/framework-bundle": "^3.3 || ^4.0", + "symfony/mercure": "*", "symfony/mercure-bundle": "*", - "symfony/messenger": "^4.2", - "symfony/phpunit-bridge": "^3.4.5 || ^4.0.5", - "symfony/routing": "^3.4 || ^4.0", - "symfony/security": "^3.4 || ^4.0", + "symfony/messenger": "^4.1", + "symfony/phpunit-bridge": "^3.3 || ^4.0", + "symfony/routing": "^3.3 || ^4.0", + "symfony/security": "^3.0 || ^4.0", "symfony/security-bundle": "^3.4 || ^4.0", "symfony/twig-bundle": "^3.4 || ^4.0", - "symfony/validator": "^3.4 || ^4.0", - "symfony/web-profiler-bundle": "^3.4 || ^4.0", - "symfony/yaml": "^3.4 || ^4.0", - "webonyx/graphql-php": ">=0.13 <1.0" + "symfony/validator": "^3.3 || ^4.0", + "symfony/web-profiler-bundle": "^3.3 || ^4.0", + "symfony/yaml": "^3.3 || ^4.0", + "webonyx/graphql-php": ">=0.12 <1.0" }, "conflict": { - "doctrine/common": "<2.7", - "doctrine/mongodb-odm": "<2.0" + "symfony/dependency-injection": "<3.4" }, "suggest": { - "doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.", - "elasticsearch/elasticsearch": "To support Elasticsearch.", "friendsofsymfony/user-bundle": "To use the FOSUserBundle bridge.", "guzzlehttp/guzzle": "To use the HTTP cache invalidation system.", "phpdocumentor/reflection-docblock": "To support extracting metadata from PHPDoc.", @@ -103,17 +96,10 @@ }, "extra": { "branch-alias": { - "dev-master": "2.5.x-dev" + "dev-master": "2.4.x-dev" } }, "config": { "sort-packages": true - }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/alanpoulain/FOSUserBundle", - "no-api": true - } - ] + } } From 11babee83e57bd55b4b7ba3ff4818fcaf291c1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 13:50:46 +0100 Subject: [PATCH 04/46] =?UTF-8?q?Add=20class=20to=20store=20the=20events?= =?UTF-8?q?=E2=80=99=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Event/ApiPlatformEvents.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Event/ApiPlatformEvents.php diff --git a/src/Event/ApiPlatformEvents.php b/src/Event/ApiPlatformEvents.php new file mode 100644 index 00000000000..d68c026fa3e --- /dev/null +++ b/src/Event/ApiPlatformEvents.php @@ -0,0 +1,20 @@ + Date: Thu, 15 Nov 2018 14:03:52 +0100 Subject: [PATCH 05/46] Convert events to Plain Old PHP Object, made them final classes --- src/Event/PostReadEvent.php | 51 +++++-------------------- src/Event/PostRespondEvent.php | 21 ++++++---- src/Event/PostSerializeEvent.php | 25 +++++------- src/Event/PreReadEvent.php | 51 +++++-------------------- src/Event/PreRespondEvent.php | 21 ++++++---- src/Event/PreSerializeEvent.php | 25 +++++------- src/EventListener/ReadListener.php | 8 ++-- src/EventListener/RespondListener.php | 4 +- src/EventListener/SerializeListener.php | 5 +-- 9 files changed, 69 insertions(+), 142 deletions(-) diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index d2d8d67bf1a..ffffb258f49 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -2,59 +2,26 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; -use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; -use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; -use ApiPlatform\Core\Identifier\IdentifierConverterInterface; -use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use Symfony\Component\EventDispatcher\Event; -class PostReadEvent extends Event +final class PostReadEvent extends Event { - const NAME = 'api_platform.post_read'; + const NAME = ApiPlatformEvents::POST_READ; - /** @var CollectionDataProviderInterface */ - protected $collectionDataProvider; - /** @var ItemDataProviderInterface */ - protected $itemDataProvider; - /** @var SubresourceDataProviderInterface */ - protected $subresourceDataProvider; - /** @var SerializerContextBuilderInterface */ - protected $serializerContextBuilder; - /** @var IdentifierConverterInterface */ - protected $identifierConverter; + private $data; - public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider = null, SerializerContextBuilderInterface $serializerContextBuilder = null, IdentifierConverterInterface $identifierConverter = null) + public function __construct($data) { - $this->collectionDataProvider = $collectionDataProvider; - $this->itemDataProvider = $itemDataProvider; - $this->subresourceDataProvider = $subresourceDataProvider; - $this->serializerContextBuilder = $serializerContextBuilder; - $this->identifierConverter = $identifierConverter; + $this->data = $data; } - public function getSerializerContextBuilder(): SerializerContextBuilderInterface + public function getData() { - return $this->serializerContextBuilder; + return $this->data; } - public function getCollectionDataProvider(): CollectionDataProviderInterface + public function setData($data): void { - return $this->collectionDataProvider; - } - - public function getIdentifierConverter(): IdentifierConverterInterface - { - return $this->identifierConverter; - } - - public function getItemDataProvider(): ItemDataProviderInterface - { - return $this->itemDataProvider; - } - - public function getSubresourceDataProvider(): SubresourceDataProviderInterface - { - return $this->subresourceDataProvider; + $this->data = $data; } } diff --git a/src/Event/PostRespondEvent.php b/src/Event/PostRespondEvent.php index eccff03b827..378dbe0781f 100644 --- a/src/Event/PostRespondEvent.php +++ b/src/Event/PostRespondEvent.php @@ -4,22 +4,27 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; -class PostRespondEvent extends Event +final class PostRespondEvent extends Event { - const NAME = 'api_platform.post_respond'; + const NAME = ApiPlatformEvents::POST_RESPOND; - protected $resourceMetadataFactory; + private $event; - public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null) + public function __construct(GetResponseForControllerResultEvent $event) { - $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->event = $event; } - public function getResourceMetadataFactory(): ResourceMetadataFactoryInterface + public function getEvent(): GetResponseForControllerResultEvent { - return $this->resourceMetadataFactory; + return $this->event; + } + + public function setEvent(GetResponseForControllerResultEvent $event): void + { + $this->event = $event; } } diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index efebe6620b3..3f90d98270c 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -4,32 +4,25 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\Serializer\SerializerInterface; -class PostSerializeEvent extends Event +final class PostSerializeEvent extends Event { - const NAME = 'api_platform.post_serialize'; + const NAME = ApiPlatformEvents::POST_SERIALIZE; + private $controllerResult; - /** @var SerializerInterface */ - protected $serializer; - /** @var SerializerContextBuilderInterface */ - protected $serializerContextBuilder; - - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder) + public function __construct($controllerResult) { - $this->serializer = $serializer; - $this->serializerContextBuilder = $serializerContextBuilder; + $this->controllerResult = $controllerResult; } - public function getSerializer(): SerializerInterface + public function getControllerResult() { - return $this->serializer; + return $this->controllerResult; } - public function getSerializerContextBuilder(): SerializerContextBuilderInterface + public function setControllerResult($controllerResult): void { - return $this->serializerContextBuilder; + $this->controllerResult = $controllerResult; } } diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index 74e3d9081bc..a616d2a369a 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -2,59 +2,26 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; -use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; -use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; -use ApiPlatform\Core\Identifier\IdentifierConverterInterface; -use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use Symfony\Component\EventDispatcher\Event; -class PreReadEvent extends Event +final class PreReadEvent extends Event { - const NAME = 'api_platform.pre_read'; + const NAME = ApiPlatformEvents::PRE_READ; - /** @var CollectionDataProviderInterface */ - protected $collectionDataProvider; - /** @var ItemDataProviderInterface */ - protected $itemDataProvider; - /** @var SubresourceDataProviderInterface */ - protected $subresourceDataProvider; - /** @var SerializerContextBuilderInterface */ - protected $serializerContextBuilder; - /** @var IdentifierConverterInterface */ - protected $identifierConverter; + private $data; - public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider = null, SerializerContextBuilderInterface $serializerContextBuilder = null, IdentifierConverterInterface $identifierConverter = null) + public function __construct($data) { - $this->collectionDataProvider = $collectionDataProvider; - $this->itemDataProvider = $itemDataProvider; - $this->subresourceDataProvider = $subresourceDataProvider; - $this->serializerContextBuilder = $serializerContextBuilder; - $this->identifierConverter = $identifierConverter; + $this->data = $data; } - public function getSerializerContextBuilder(): SerializerContextBuilderInterface + public function getData() { - return $this->serializerContextBuilder; + return $this->data; } - public function getCollectionDataProvider(): CollectionDataProviderInterface + public function setData($data): void { - return $this->collectionDataProvider; - } - - public function getIdentifierConverter(): IdentifierConverterInterface - { - return $this->identifierConverter; - } - - public function getItemDataProvider(): ItemDataProviderInterface - { - return $this->itemDataProvider; - } - - public function getSubresourceDataProvider(): SubresourceDataProviderInterface - { - return $this->subresourceDataProvider; + $this->data = $data; } } diff --git a/src/Event/PreRespondEvent.php b/src/Event/PreRespondEvent.php index e7c553dd9aa..0f0a3a8f15e 100644 --- a/src/Event/PreRespondEvent.php +++ b/src/Event/PreRespondEvent.php @@ -4,22 +4,27 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; -class PreRespondEvent extends Event +final class PreRespondEvent extends Event { - const NAME = 'api_platform.pre_respond'; + const NAME = ApiPlatformEvents::PRE_RESPOND; - protected $resourceMetadataFactory; + private $event; - public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null) + public function __construct(GetResponseForControllerResultEvent $event) { - $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->event = $event; } - public function getResourceMetadataFactory(): ResourceMetadataFactoryInterface + public function getEvent(): GetResponseForControllerResultEvent { - return $this->resourceMetadataFactory; + return $this->event; + } + + public function setEvent(GetResponseForControllerResultEvent $event): void + { + $this->event = $event; } } diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index bf349fae9f3..103ff9a63a9 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -4,32 +4,25 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\Serializer\SerializerInterface; -class PreSerializeEvent extends Event +final class PreSerializeEvent extends Event { - const NAME = 'api_platform.pre_serialize'; + const NAME = ApiPlatformEvents::PRE_SERIALIZE; + private $controllerResult; - /** @var SerializerInterface */ - protected $serializer; - /** @var SerializerContextBuilderInterface */ - protected $serializerContextBuilder; - - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder) + public function __construct($controllerResult) { - $this->serializer = $serializer; - $this->serializerContextBuilder = $serializerContextBuilder; + $this->controllerResult = $controllerResult; } - public function getSerializer(): SerializerInterface + public function getControllerResult() { - return $this->serializer; + return $this->controllerResult; } - public function getSerializerContextBuilder(): SerializerContextBuilderInterface + public function setControllerResult($controllerResult): void { - return $this->serializerContextBuilder; + $this->controllerResult = $controllerResult; } } diff --git a/src/EventListener/ReadListener.php b/src/EventListener/ReadListener.php index d3af9ea0ed9..777cc5a773d 100644 --- a/src/EventListener/ReadListener.php +++ b/src/EventListener/ReadListener.php @@ -26,7 +26,6 @@ use ApiPlatform\Core\Util\RequestAttributesExtractor; use ApiPlatform\Core\Util\RequestParser; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -95,7 +94,7 @@ public function onKernelRequest(GetResponseEvent $event) try { $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes); - $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($this->collectionDataProvider, $this->itemDataProvider, $this->subresourceDataProvider, $this->serializerContextBuilder, $this->identifierConverter)); + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($data)); if (isset($attributes['item_operation_name'])) { $data = $this->getItemData($identifiers, $attributes, $context); @@ -107,13 +106,12 @@ public function onKernelRequest(GetResponseEvent $event) $data = $this->getSubresourceData($identifiers, $attributes, $context); } - - $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($this->collectionDataProvider, $this->itemDataProvider, $this->subresourceDataProvider, $this->serializerContextBuilder, $this->identifierConverter)); - } catch (InvalidIdentifierException $e) { throw new NotFoundHttpException('Not found, because of an invalid identifier configuration', $e); } + $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data)); + if (null === $data) { throw new NotFoundHttpException('Not Found'); } diff --git a/src/EventListener/RespondListener.php b/src/EventListener/RespondListener.php index adcaa7f3ad4..152f52922cc 100644 --- a/src/EventListener/RespondListener.php +++ b/src/EventListener/RespondListener.php @@ -81,7 +81,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $status = $resourceMetadata->getOperationAttribute($attributes, 'status'); } - $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($this->resourceMetadataFactory)); + $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($event)); $event->setResponse(new Response( $controllerResult, @@ -89,6 +89,6 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $headers )); - $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($this->resourceMetadataFactory)); + $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($event)); } } diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index a3e650fed38..af242e865af 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -19,7 +19,6 @@ use ApiPlatform\Core\Serializer\ResourceList; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -77,11 +76,11 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $request->attributes->set('_api_normalization_context', $context); - $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($this->serializer, $this->serializerContextBuilder)); + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($controllerResult)); $event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context)); - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($this->serializer, $this->serializerContextBuilder)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($controllerResult)); $request->attributes->set('_api_respond', true); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + (array) $resources); From a78263d645414fec4bf09b1b446a3dd3ff40fe41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 14:32:59 +0100 Subject: [PATCH 06/46] Add Write events --- .../Symfony/Bundle/Resources/config/api.xml | 1 + src/Event/PostWriteEvent.php | 38 +++++++++++++++++++ src/Event/PreWriteEvent.php | 38 +++++++++++++++++++ src/EventListener/WriteListener.php | 19 +++++++--- 4 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 src/Event/PostWriteEvent.php create mode 100644 src/Event/PreWriteEvent.php diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index bc600762079..9f1fc8d7e13 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -157,6 +157,7 @@ + diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php new file mode 100644 index 00000000000..123dde06071 --- /dev/null +++ b/src/Event/PostWriteEvent.php @@ -0,0 +1,38 @@ +method = $method; + $this->controllerResult = $controllerResult; + } + + public function getMethod(): string + { + return $this->method; + } + + public function setMethod(string $method): void + { + $this->method = $method; + } + + public function getControllerResult() + { + return $this->controllerResult; + } + + public function setControllerResult($controllerResult): void + { + $this->controllerResult = $controllerResult; + } +} diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php new file mode 100644 index 00000000000..506371f4d3b --- /dev/null +++ b/src/Event/PreWriteEvent.php @@ -0,0 +1,38 @@ +method = $method; + $this->controllerResult = $controllerResult; + } + + public function getMethod(): string + { + return $this->method; + } + + public function setMethod(string $method): void + { + $this->method = $method; + } + + public function getControllerResult() + { + return $this->controllerResult; + } + + public function setControllerResult($controllerResult): void + { + $this->controllerResult = $controllerResult; + } +} diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index 7b222971e0a..4c830e8eed8 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -15,11 +15,14 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; -use ApiPlatform\Core\Util\RequestAttributesExtractor; +use ApiPlatform\Core\Event\PostWriteEvent; +use ApiPlatform\Core\Event\PreRespondEvent; +use ApiPlatform\Core\Event\PreWriteEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; /** - * Bridges persistence and the API system. + * Bridges persistense and the API system. * * @author Kévin Dunglas * @author Baptiste Meyer @@ -28,11 +31,13 @@ final class WriteListener { private $dataPersister; private $iriConverter; + private $dispatcher; - public function __construct(DataPersisterInterface $dataPersister, IriConverterInterface $iriConverter = null) + public function __construct(DataPersisterInterface $dataPersister, IriConverterInterface $iriConverter = null, EventDispatcherInterface $dispatcher = null) { $this->dataPersister = $dataPersister; $this->iriConverter = $iriConverter; + $this->dispatcher = $dispatcher; } /** @@ -41,7 +46,7 @@ public function __construct(DataPersisterInterface $dataPersister, IriConverterI public function onKernelView(GetResponseForControllerResultEvent $event) { $request = $event->getRequest(); - if ($request->isMethodSafe(false) || !$request->attributes->getBoolean('_api_persist', true) || !$attributes = RequestAttributesExtractor::extractAttributes($request)) { + if ($request->isMethodSafe(false) || !$request->attributes->has('_api_resource_class') || !$request->attributes->getBoolean('_api_persist', true)) { return; } @@ -50,11 +55,14 @@ public function onKernelView(GetResponseForControllerResultEvent $event) return; } + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($request->getMethod(), $controllerResult)); + switch ($request->getMethod()) { case 'PUT': case 'PATCH': case 'POST': $persistResult = $this->dataPersister->persist($controllerResult); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); if (null === $persistResult) { @trigger_error(sprintf('Returning void from %s::persist() is deprecated since API Platform 2.3 and will not be supported in API Platform 3, an object should always be returned.', DataPersisterInterface::class), E_USER_DEPRECATED); @@ -65,12 +73,13 @@ public function onKernelView(GetResponseForControllerResultEvent $event) // Controller result must be immutable for _api_write_item_iri // if it's class changed compared to the base class let's avoid calling the IriConverter // especially that the Output class could be a DTO that's not referencing any route - if (null !== $this->iriConverter && (false !== $attributes['output_class'] ?? null) && $attributes['resource_class'] === ($class = \get_class($controllerResult)) && $class === \get_class($event->getControllerResult())) { + if (null !== $this->iriConverter && \get_class($controllerResult) === \get_class($event->getControllerResult())) { $request->attributes->set('_api_write_item_iri', $this->iriConverter->getIriFromItem($controllerResult)); } break; case 'DELETE': $this->dataPersister->remove($controllerResult); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); $event->setControllerResult(null); break; } From 435e08be6a37c197f0ff16d9837703a67cca2344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 14:49:53 +0100 Subject: [PATCH 07/46] Add 'add format' events --- .../Symfony/Bundle/Resources/config/api.xml | 1 + src/Event/ApiPlatformEvents.php | 3 ++ src/Event/PostAddFormatEvent.php | 28 +++++++++++++++ src/Event/PreAddFormatEvent.php | 28 +++++++++++++++ src/EventListener/AddFormatListener.php | 36 ++++++++++--------- 5 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 src/Event/PostAddFormatEvent.php create mode 100644 src/Event/PreAddFormatEvent.php diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index 9f1fc8d7e13..db9a9914efe 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -139,6 +139,7 @@ + diff --git a/src/Event/ApiPlatformEvents.php b/src/Event/ApiPlatformEvents.php index d68c026fa3e..4bbefc89c14 100644 --- a/src/Event/ApiPlatformEvents.php +++ b/src/Event/ApiPlatformEvents.php @@ -17,4 +17,7 @@ final class ApiPlatformEvents const PRE_RESPOND = 'api_platform.pre_respond'; const POST_RESPOND = 'api_platform.post_respond'; + + const PRE_ADD_FORMAT = 'api_platform.pre_add_format'; + const POST_ADD_FORMAT = 'api_platform.post_add_format'; } diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php new file mode 100644 index 00000000000..fc4754786a6 --- /dev/null +++ b/src/Event/PostAddFormatEvent.php @@ -0,0 +1,28 @@ +formats = $formats; + } + + public function getFormats() + { + return $this->formats; + } + + public function setFormats($formats): void + { + $this->formats = $formats; + } +} diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php new file mode 100644 index 00000000000..189d29ae908 --- /dev/null +++ b/src/Event/PreAddFormatEvent.php @@ -0,0 +1,28 @@ +formats = $formats; + } + + public function getFormats() + { + return $this->formats; + } + + public function setFormats($formats): void + { + $this->formats = $formats; + } +} diff --git a/src/EventListener/AddFormatListener.php b/src/EventListener/AddFormatListener.php index 72e53713dda..457b2e1d5e6 100644 --- a/src/EventListener/AddFormatListener.php +++ b/src/EventListener/AddFormatListener.php @@ -13,18 +13,20 @@ namespace ApiPlatform\Core\EventListener; -use ApiPlatform\Core\Api\FormatMatcher; use ApiPlatform\Core\Api\FormatsProviderInterface; +use ApiPlatform\Core\Event\PostAddFormatEvent; +use ApiPlatform\Core\Event\PreAddFormatEvent; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Util\RequestAttributesExtractor; use Negotiation\Negotiator; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** - * Chooses the format to use according to the Accept header and supported formats. + * Chooses the format to user according to the Accept header and supported formats. * * @author Kévin Dunglas */ @@ -34,29 +36,32 @@ final class AddFormatListener private $formats = []; private $mimeTypes; private $formatsProvider; - private $formatMatcher; + private $dispatcher; /** * @throws InvalidArgumentException */ - public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider) + public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher) { $this->negotiator = $negotiator; if (\is_array($formatsProvider)) { @trigger_error('Using an array as formats provider is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3', E_USER_DEPRECATED); $this->formats = $formatsProvider; - } else { - if (!$formatsProvider instanceof FormatsProviderInterface) { - throw new InvalidArgumentException(sprintf('The "$formatsProvider" argument is expected to be an implementation of the "%s" interface.', FormatsProviderInterface::class)); - } - $this->formatsProvider = $formatsProvider; + return; + } + if (!$formatsProvider instanceof FormatsProviderInterface) { + throw new InvalidArgumentException(sprintf('The "$formatsProvider" argument is expected to be an implementation of the "%s" interface.', FormatsProviderInterface::class)); } + + $this->formatsProvider = $formatsProvider; + $this->dispatcher = $dispatcher; } /** * Sets the applicable format to the HttpFoundation Request. * + * * @throws NotFoundHttpException * @throws NotAcceptableHttpException */ @@ -70,10 +75,11 @@ public function onKernelRequest(GetResponseEvent $event) if (null !== $this->formatsProvider) { $this->formats = $this->formatsProvider->getFormatsFromAttributes(RequestAttributesExtractor::extractAttributes($request)); } - $this->formatMatcher = new FormatMatcher($this->formats); $this->populateMimeTypes(); + $this->dispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent($this->formats)); $this->addRequestFormats($request, $this->formats); + $this->dispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent($this->formats)); // Empty strings must be converted to null because the Symfony router doesn't support parameter typing before 3.2 (_format) if (null === $routeFormat = $request->attributes->get('_format') ?: null) { @@ -88,11 +94,11 @@ public function onKernelRequest(GetResponseEvent $event) /** @var string|null $accept */ $accept = $request->headers->get('Accept'); if (null !== $accept) { - if (null === $mediaType = $this->negotiator->getBest($accept, $mimeTypes)) { + if (null === $acceptHeader = $this->negotiator->getBest($accept, $mimeTypes)) { throw $this->getNotAcceptableHttpException($accept, $mimeTypes); } - $request->setRequestFormat($this->formatMatcher->getFormat($mediaType->getType())); + $request->setRequestFormat($request->getFormat($acceptHeader->getType())); return; } @@ -118,14 +124,12 @@ public function onKernelRequest(GetResponseEvent $event) } /** - * Adds the supported formats to the request. - * - * This is necessary for {@see Request::getMimeType} and {@see Request::getMimeTypes} to work. + * Adds API formats to the HttpFoundation Request. */ private function addRequestFormats(Request $request, array $formats) { foreach ($formats as $format => $mimeTypes) { - $request->setFormat($format, (array) $mimeTypes); + $request->setFormat($format, $mimeTypes); } } From b8117d7fc75204ad290bedbf1ea4b75fa205fd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 15:37:41 +0100 Subject: [PATCH 08/46] Add deserialize events --- .../Symfony/Bundle/Resources/config/api.xml | 1 + src/Event/ApiPlatformEvents.php | 3 ++ src/Event/PostDeserializeEvent.php | 28 +++++++++++++++++ src/Event/PreDeserializeEvent.php | 28 +++++++++++++++++ src/EventListener/DeserializeListener.php | 31 +++++++++++-------- 5 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 src/Event/PostDeserializeEvent.php create mode 100644 src/Event/PreDeserializeEvent.php diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index db9a9914efe..ba60b4aaf40 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -167,6 +167,7 @@ + diff --git a/src/Event/ApiPlatformEvents.php b/src/Event/ApiPlatformEvents.php index 4bbefc89c14..9124702402e 100644 --- a/src/Event/ApiPlatformEvents.php +++ b/src/Event/ApiPlatformEvents.php @@ -15,6 +15,9 @@ final class ApiPlatformEvents const PRE_SERIALIZE = 'api_platform.pre_serialize'; const POST_SERIALIZE = 'api_platform.post_serialize'; + const PRE_DESERIALIZE = 'api_platform.pre_deserialize'; + const POST_DESERIALIZE = 'api_platform.post_deserialize'; + const PRE_RESPOND = 'api_platform.pre_respond'; const POST_RESPOND = 'api_platform.post_respond'; diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php new file mode 100644 index 00000000000..450849415b6 --- /dev/null +++ b/src/Event/PostDeserializeEvent.php @@ -0,0 +1,28 @@ +controllerResult = $controllerResult; + } + + public function getControllerResult() + { + return $this->controllerResult; + } + + public function setControllerResult($controllerResult): void + { + $this->controllerResult = $controllerResult; + } +} diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php new file mode 100644 index 00000000000..31558b475b2 --- /dev/null +++ b/src/Event/PreDeserializeEvent.php @@ -0,0 +1,28 @@ +controllerResult = $controllerResult; + } + + public function getControllerResult() + { + return $this->controllerResult; + } + + public function setControllerResult($controllerResult): void + { + $this->controllerResult = $controllerResult; + } +} diff --git a/src/EventListener/DeserializeListener.php b/src/EventListener/DeserializeListener.php index 1fff5848178..cc8d481c829 100644 --- a/src/EventListener/DeserializeListener.php +++ b/src/EventListener/DeserializeListener.php @@ -13,11 +13,13 @@ namespace ApiPlatform\Core\EventListener; -use ApiPlatform\Core\Api\FormatMatcher; use ApiPlatform\Core\Api\FormatsProviderInterface; +use ApiPlatform\Core\Event\PostDeserializeEvent; +use ApiPlatform\Core\Event\PreDeserializeEvent; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; @@ -35,25 +37,27 @@ final class DeserializeListener private $serializerContextBuilder; private $formats = []; private $formatsProvider; - private $formatMatcher; + private $dispatcher; /** * @throws InvalidArgumentException */ - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */ $formatsProvider) + public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher) { $this->serializer = $serializer; $this->serializerContextBuilder = $serializerContextBuilder; if (\is_array($formatsProvider)) { @trigger_error('Using an array as formats provider is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3', E_USER_DEPRECATED); $this->formats = $formatsProvider; - } else { - if (!$formatsProvider instanceof FormatsProviderInterface) { - throw new InvalidArgumentException(sprintf('The "$formatsProvider" argument is expected to be an implementation of the "%s" interface.', FormatsProviderInterface::class)); - } - $this->formatsProvider = $formatsProvider; + return; + } + if (!$formatsProvider instanceof FormatsProviderInterface) { + throw new InvalidArgumentException(sprintf('The "$formatsProvider" argument is expected to be an implementation of the "%s" interface.', FormatsProviderInterface::class)); } + + $this->formatsProvider = $formatsProvider; + $this->dispatcher = $dispatcher; } /** @@ -64,10 +68,9 @@ public function onKernelRequest(GetResponseEvent $event) $request = $event->getRequest(); $method = $request->getMethod(); if ( - 'DELETE' === $method - || $request->isMethodSafe(false) + $request->isMethodSafe(false) + || 'DELETE' === $method || !($attributes = RequestAttributesExtractor::extractAttributes($request)) - || false === ($attributes['input_class'] ?? null) || !$attributes['receive'] || ( '' === ($requestContent = $request->getContent()) @@ -80,7 +83,6 @@ public function onKernelRequest(GetResponseEvent $event) if (null !== $this->formatsProvider) { $this->formats = $this->formatsProvider->getFormatsFromAttributes($attributes); } - $this->formatMatcher = new FormatMatcher($this->formats); $format = $this->getFormat($request); $context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes); @@ -93,17 +95,20 @@ public function onKernelRequest(GetResponseEvent $event) $context[AbstractNormalizer::OBJECT_TO_POPULATE] = $data; } + $this->dispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($requestContent)); $request->attributes->set( 'data', $this->serializer->deserialize( $requestContent, $attributes['input_class'], $format, $context ) ); + $this->dispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($requestContent)); } /** * Extracts the format from the Content-Type header and check that it is supported. * + * * @throws NotAcceptableHttpException */ private function getFormat(Request $request): string @@ -116,7 +121,7 @@ private function getFormat(Request $request): string throw new NotAcceptableHttpException('The "Content-Type" header must exist.'); } - $format = $this->formatMatcher->getFormat($contentType); + $format = $request->getFormat($contentType); if (null === $format || !isset($this->formats[$format])) { $supportedMimeTypes = []; foreach ($this->formats as $mimeTypes) { From 24d8deeaf251e87a493081459e89ed078749e31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 15:55:10 +0100 Subject: [PATCH 09/46] Meeting coding standard --- src/Event/ApiPlatformEvents.php | 11 ++++++++++- src/Event/PostAddFormatEvent.php | 11 ++++++++++- src/Event/PostDeserializeEvent.php | 11 ++++++++++- src/Event/PostReadEvent.php | 11 +++++++++++ src/Event/PostRespondEvent.php | 11 ++++++++++- src/Event/PostSerializeEvent.php | 11 ++++++++++- src/Event/PostWriteEvent.php | 11 +++++++++++ src/Event/PreAddFormatEvent.php | 11 ++++++++++- src/Event/PreDeserializeEvent.php | 11 ++++++++++- src/Event/PreReadEvent.php | 11 +++++++++++ src/Event/PreRespondEvent.php | 11 ++++++++++- src/Event/PreSerializeEvent.php | 11 ++++++++++- src/Event/PreWriteEvent.php | 11 +++++++++++ src/EventListener/SerializeListener.php | 1 - src/EventListener/WriteListener.php | 1 - 15 files changed, 134 insertions(+), 11 deletions(-) diff --git a/src/Event/ApiPlatformEvents.php b/src/Event/ApiPlatformEvents.php index 9124702402e..9f48c0d3729 100644 --- a/src/Event/ApiPlatformEvents.php +++ b/src/Event/ApiPlatformEvents.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; final class ApiPlatformEvents { diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php index fc4754786a6..e7c369968ed 100644 --- a/src/Event/PostAddFormatEvent.php +++ b/src/Event/PostAddFormatEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php index 450849415b6..5a9f4b562a9 100644 --- a/src/Event/PostDeserializeEvent.php +++ b/src/Event/PostDeserializeEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index ffffb258f49..28767f6dcb1 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -1,5 +1,16 @@ + * + * 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\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PostRespondEvent.php b/src/Event/PostRespondEvent.php index 378dbe0781f..a9985b71830 100644 --- a/src/Event/PostRespondEvent.php +++ b/src/Event/PostRespondEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index 3f90d98270c..9bee0271fbd 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index 123dde06071..a0baf1bc1ec 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -1,5 +1,16 @@ + * + * 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\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php index 189d29ae908..f846d08cae4 100644 --- a/src/Event/PreAddFormatEvent.php +++ b/src/Event/PreAddFormatEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index 31558b475b2..c053de72002 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index a616d2a369a..07ea4c9f9e6 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -1,5 +1,16 @@ + * + * 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\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreRespondEvent.php b/src/Event/PreRespondEvent.php index 0f0a3a8f15e..d5d2637ed91 100644 --- a/src/Event/PreRespondEvent.php +++ b/src/Event/PreRespondEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index 103ff9a63a9..b5b88a3c2a6 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index 506371f4d3b..fc7f16a3548 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -1,5 +1,16 @@ + * + * 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\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index af242e865af..0b49c7e52c3 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -84,7 +84,6 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $request->attributes->set('_api_respond', true); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + (array) $resources); - } /** diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index 4c830e8eed8..4846a2f0fa5 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -16,7 +16,6 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; use ApiPlatform\Core\Event\PostWriteEvent; -use ApiPlatform\Core\Event\PreRespondEvent; use ApiPlatform\Core\Event\PreWriteEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; From 694ba6686619dbca0b0639e3699217e9c974bcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 15 Nov 2018 16:13:14 +0100 Subject: [PATCH 10/46] Fix BC break --- src/EventListener/AddFormatListener.php | 13 ++++++++++--- src/EventListener/DeserializeListener.php | 12 +++++++++--- src/EventListener/ReadListener.php | 8 ++++++-- src/EventListener/RespondListener.php | 8 ++++++-- src/EventListener/SerializeListener.php | 10 +++++++--- src/EventListener/WriteListener.php | 15 ++++++++++++--- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/EventListener/AddFormatListener.php b/src/EventListener/AddFormatListener.php index 457b2e1d5e6..21023f0d1c7 100644 --- a/src/EventListener/AddFormatListener.php +++ b/src/EventListener/AddFormatListener.php @@ -41,7 +41,7 @@ final class AddFormatListener /** * @throws InvalidArgumentException */ - public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher) + public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher = null) { $this->negotiator = $negotiator; if (\is_array($formatsProvider)) { @@ -77,9 +77,16 @@ public function onKernelRequest(GetResponseEvent $event) } $this->populateMimeTypes(); - $this->dispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent($this->formats)); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent($this->formats)); + } + $this->addRequestFormats($request, $this->formats); - $this->dispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent($this->formats)); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent($this->formats)); + } // Empty strings must be converted to null because the Symfony router doesn't support parameter typing before 3.2 (_format) if (null === $routeFormat = $request->attributes->get('_format') ?: null) { diff --git a/src/EventListener/DeserializeListener.php b/src/EventListener/DeserializeListener.php index cc8d481c829..4f895f6cda6 100644 --- a/src/EventListener/DeserializeListener.php +++ b/src/EventListener/DeserializeListener.php @@ -42,7 +42,7 @@ final class DeserializeListener /** * @throws InvalidArgumentException */ - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher) + public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher = null) { $this->serializer = $serializer; $this->serializerContextBuilder = $serializerContextBuilder; @@ -95,14 +95,20 @@ public function onKernelRequest(GetResponseEvent $event) $context[AbstractNormalizer::OBJECT_TO_POPULATE] = $data; } - $this->dispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($requestContent)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($requestContent)); + } + $request->attributes->set( 'data', $this->serializer->deserialize( $requestContent, $attributes['input_class'], $format, $context ) ); - $this->dispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($requestContent)); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($requestContent)); + } } /** diff --git a/src/EventListener/ReadListener.php b/src/EventListener/ReadListener.php index 777cc5a773d..c51497cb64f 100644 --- a/src/EventListener/ReadListener.php +++ b/src/EventListener/ReadListener.php @@ -94,7 +94,9 @@ public function onKernelRequest(GetResponseEvent $event) try { $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes); - $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($data)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($data)); + } if (isset($attributes['item_operation_name'])) { $data = $this->getItemData($identifiers, $attributes, $context); @@ -110,7 +112,9 @@ public function onKernelRequest(GetResponseEvent $event) throw new NotFoundHttpException('Not found, because of an invalid identifier configuration', $e); } - $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data)); + } if (null === $data) { throw new NotFoundHttpException('Not Found'); diff --git a/src/EventListener/RespondListener.php b/src/EventListener/RespondListener.php index 152f52922cc..9546ce7e162 100644 --- a/src/EventListener/RespondListener.php +++ b/src/EventListener/RespondListener.php @@ -81,7 +81,9 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $status = $resourceMetadata->getOperationAttribute($attributes, 'status'); } - $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($event)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($event)); + } $event->setResponse(new Response( $controllerResult, @@ -89,6 +91,8 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $headers )); - $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($event)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($event)); + } } } diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index 0b49c7e52c3..bcb090cfea7 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -39,7 +39,7 @@ final class SerializeListener /** @var EventDispatcherInterface */ private $dispatcher; - public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, EventDispatcherInterface $dispatcher) + public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, EventDispatcherInterface $dispatcher = null) { $this->serializer = $serializer; $this->serializerContextBuilder = $serializerContextBuilder; @@ -76,11 +76,15 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $request->attributes->set('_api_normalization_context', $context); - $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($controllerResult)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($controllerResult)); + } $event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context)); - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($controllerResult)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($controllerResult)); + } $request->attributes->set('_api_respond', true); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + (array) $resources); diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index 4846a2f0fa5..af5f9899c33 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -54,14 +54,19 @@ public function onKernelView(GetResponseForControllerResultEvent $event) return; } - $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($request->getMethod(), $controllerResult)); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($request->getMethod(), $controllerResult)); + } switch ($request->getMethod()) { case 'PUT': case 'PATCH': case 'POST': $persistResult = $this->dataPersister->persist($controllerResult); - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + } if (null === $persistResult) { @trigger_error(sprintf('Returning void from %s::persist() is deprecated since API Platform 2.3 and will not be supported in API Platform 3, an object should always be returned.', DataPersisterInterface::class), E_USER_DEPRECATED); @@ -78,7 +83,11 @@ public function onKernelView(GetResponseForControllerResultEvent $event) break; case 'DELETE': $this->dataPersister->remove($controllerResult); - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + } + $event->setControllerResult(null); break; } From e3523530b7fda95f7c5f7fd59b567c8cb21788ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 14:49:40 +0100 Subject: [PATCH 11/46] GraphQL: raising the new Pre/PostWriteEvent when mutating item --- .../Bundle/Resources/config/graphql.xml | 1 + .../Factory/ItemMutationResolverFactory.php | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml index bdc491d1b38..ac8e971607b 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml @@ -27,6 +27,7 @@ + diff --git a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php index 46f77aa08b5..c78f11e3cdc 100644 --- a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php @@ -15,6 +15,8 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; +use ApiPlatform\Core\Event\PostWriteEvent; +use ApiPlatform\Core\Event\PreWriteEvent; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Exception\ItemNotFoundException; use ApiPlatform\Core\GraphQl\Resolver\FieldsToAttributesTrait; @@ -28,6 +30,7 @@ use ApiPlatform\Core\Validator\ValidatorInterface; use GraphQL\Error\Error; use GraphQL\Type\Definition\ResolveInfo; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -50,8 +53,12 @@ final class ItemMutationResolverFactory implements ResolverFactoryInterface private $resourceMetadataFactory; private $resourceAccessChecker; private $validator; + /** + * @var EventDispatcherInterface + */ + private $dispatcher; - public function __construct(IriConverterInterface $iriConverter, DataPersisterInterface $dataPersister, NormalizerInterface $normalizer, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, ValidatorInterface $validator = null) + public function __construct(IriConverterInterface $iriConverter, DataPersisterInterface $dataPersister, NormalizerInterface $normalizer, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, ValidatorInterface $validator = null, EventDispatcherInterface $dispatcher = null) { if (!$normalizer instanceof DenormalizerInterface) { throw new InvalidArgumentException(sprintf('The normalizer must implements the "%s" interface', DenormalizerInterface::class)); @@ -63,6 +70,7 @@ public function __construct(IriConverterInterface $iriConverter, DataPersisterIn $this->resourceMetadataFactory = $resourceMetadataFactory; $this->resourceAccessChecker = $resourceAccessChecker; $this->validator = $validator; + $this->dispatcher = $dispatcher; } public function __invoke(string $resourceClass = null, string $rootClass = null, string $operationName = null): callable @@ -104,20 +112,37 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $context += $resourceMetadata->getGraphqlAttribute($operationName, 'denormalization_context', [], true); $item = $this->normalizer->denormalize($args['input'], $resourceClass, ItemNormalizer::FORMAT, $context); $this->validate($item, $info, $resourceMetadata, $operationName); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($operationName, $item)); + } + $persistResult = $this->dataPersister->persist($item); + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($operationName, $item)); + } + if (null === $persistResult) { @trigger_error(sprintf('Returning void from %s::persist() is deprecated since API Platform 2.3 and will not be supported in API Platform 3, an object should always be returned.', DataPersisterInterface::class), E_USER_DEPRECATED); } return $this->normalizer->normalize($persistResult ?? $item, ItemNormalizer::FORMAT, $normalizationContext) + $data; case 'delete': + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($operationName, $item)); + } + if ($item) { $this->dataPersister->remove($item); $data['id'] = $args['input']['id']; } else { $data['id'] = null; } + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($operationName, $item)); + } } return $data; From 530d34ae59318e9ebb48ba0acc805bb4a5cd40b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 15:09:10 +0100 Subject: [PATCH 12/46] Remove useless PhpDoc --- src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php index c78f11e3cdc..1c473682385 100644 --- a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php @@ -53,9 +53,6 @@ final class ItemMutationResolverFactory implements ResolverFactoryInterface private $resourceMetadataFactory; private $resourceAccessChecker; private $validator; - /** - * @var EventDispatcherInterface - */ private $dispatcher; public function __construct(IriConverterInterface $iriConverter, DataPersisterInterface $dataPersister, NormalizerInterface $normalizer, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, ValidatorInterface $validator = null, EventDispatcherInterface $dispatcher = null) From 5da445ee64be7ad77c121bec6d3c28c486310419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 15:17:37 +0100 Subject: [PATCH 13/46] GraphQL: raising the new Pre/PostReadItem --- .../Symfony/Bundle/Resources/config/graphql.xml | 1 + src/GraphQl/Resolver/ItemResolver.php | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml index ac8e971607b..ad4f2b7ab05 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml @@ -35,6 +35,7 @@ + diff --git a/src/GraphQl/Resolver/ItemResolver.php b/src/GraphQl/Resolver/ItemResolver.php index a06dbb05192..40a7c9ef15b 100644 --- a/src/GraphQl/Resolver/ItemResolver.php +++ b/src/GraphQl/Resolver/ItemResolver.php @@ -14,12 +14,15 @@ namespace ApiPlatform\Core\GraphQl\Resolver; use ApiPlatform\Core\Api\IriConverterInterface; +use ApiPlatform\Core\Event\PostReadEvent; +use ApiPlatform\Core\Event\PreReadEvent; use ApiPlatform\Core\Exception\ItemNotFoundException; use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Security\ResourceAccessCheckerInterface; use ApiPlatform\Core\Util\ClassInfoTrait; use GraphQL\Type\Definition\ResolveInfo; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -40,13 +43,15 @@ final class ItemResolver private $resourceAccessChecker; private $normalizer; private $resourceMetadataFactory; + private $dispatcher; - public function __construct(IriConverterInterface $iriConverter, NormalizerInterface $normalizer, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null) + public function __construct(IriConverterInterface $iriConverter, NormalizerInterface $normalizer, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, EventDispatcherInterface $dispatcher = null) { $this->iriConverter = $iriConverter; $this->normalizer = $normalizer; $this->resourceMetadataFactory = $resourceMetadataFactory; $this->resourceAccessChecker = $resourceAccessChecker; + $this->dispatcher = $dispatcher; } public function __invoke($source, $args, $context, ResolveInfo $info) @@ -62,7 +67,15 @@ public function __invoke($source, $args, $context, ResolveInfo $info) $baseNormalizationContext = ['attributes' => $this->fieldsToAttributes($info)]; try { + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent(null)); + } + $item = $this->iriConverter->getItemFromIri($args['id'], $baseNormalizationContext); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($item)); + } } catch (ItemNotFoundException $e) { return null; } From 3b104cabe375d2e2a74c743059b7f313913c7fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 15:41:49 +0100 Subject: [PATCH 14/46] GraphQL: raising the new Pre/PostSerializeEvent on normalizing item --- src/GraphQl/Resolver/ItemResolver.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/GraphQl/Resolver/ItemResolver.php b/src/GraphQl/Resolver/ItemResolver.php index 40a7c9ef15b..c7553c1a4e7 100644 --- a/src/GraphQl/Resolver/ItemResolver.php +++ b/src/GraphQl/Resolver/ItemResolver.php @@ -15,7 +15,9 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\Event\PostReadEvent; +use ApiPlatform\Core\Event\PostSerializeEvent; use ApiPlatform\Core\Event\PreReadEvent; +use ApiPlatform\Core\Event\PreSerializeEvent; use ApiPlatform\Core\Exception\ItemNotFoundException; use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; @@ -86,6 +88,16 @@ public function __invoke($source, $args, $context, ResolveInfo $info) $normalizationContext = $resourceMetadata->getGraphqlAttribute('query', 'normalization_context', [], true); - return $this->normalizer->normalize($item, ItemNormalizer::FORMAT, $normalizationContext + $baseNormalizationContext); + if($this->dispatcher !== null) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($item)); + } + + $normalizedObject = $this->normalizer->normalize($item, ItemNormalizer::FORMAT, $normalizationContext + $baseNormalizationContext); + + if($this->dispatcher !== null) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($item)); + } + + return $normalizedObject; } } From 9fe38db33acd8bede8c77a93752d8c18cc2709f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 15:42:42 +0100 Subject: [PATCH 15/46] Rename $controllerResult field to $object --- src/Event/PreSerializeEvent.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index b5b88a3c2a6..78bb57f3eb1 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -18,20 +18,20 @@ final class PreSerializeEvent extends Event { const NAME = ApiPlatformEvents::PRE_SERIALIZE; - private $controllerResult; + private $object; - public function __construct($controllerResult) + public function __construct($object) { - $this->controllerResult = $controllerResult; + $this->object = $object; } - public function getControllerResult() + public function getObject() { - return $this->controllerResult; + return $this->object; } - public function setControllerResult($controllerResult): void + public function setObject($object): void { - $this->controllerResult = $controllerResult; + $this->object = $object; } } From df4b30cb0cf6020af27d70282f074510963df11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 15:42:42 +0100 Subject: [PATCH 16/46] Rename $controllerResult field to $object --- src/Event/PostSerializeEvent.php | 14 +++++++------- src/GraphQl/Resolver/ItemResolver.php | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index 9bee0271fbd..5dc1fee4f02 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -18,20 +18,20 @@ final class PostSerializeEvent extends Event { const NAME = ApiPlatformEvents::POST_SERIALIZE; - private $controllerResult; + private $object; - public function __construct($controllerResult) + public function __construct($object) { - $this->controllerResult = $controllerResult; + $this->object = $object; } - public function getControllerResult() + public function getObject() { - return $this->controllerResult; + return $this->object; } - public function setControllerResult($controllerResult): void + public function setObject($object): void { - $this->controllerResult = $controllerResult; + $this->object = $object; } } diff --git a/src/GraphQl/Resolver/ItemResolver.php b/src/GraphQl/Resolver/ItemResolver.php index c7553c1a4e7..74ecfb3c2ef 100644 --- a/src/GraphQl/Resolver/ItemResolver.php +++ b/src/GraphQl/Resolver/ItemResolver.php @@ -88,13 +88,13 @@ public function __invoke($source, $args, $context, ResolveInfo $info) $normalizationContext = $resourceMetadata->getGraphqlAttribute('query', 'normalization_context', [], true); - if($this->dispatcher !== null) { + if (null !== $this->dispatcher) { $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($item)); } $normalizedObject = $this->normalizer->normalize($item, ItemNormalizer::FORMAT, $normalizationContext + $baseNormalizationContext); - if($this->dispatcher !== null) { + if (null !== $this->dispatcher) { $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($item)); } From 342d0105f3677e0787c13e5be90ec474bc51bac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 16:07:13 +0100 Subject: [PATCH 17/46] GraphQL: raising the new events on the collection resolver factory --- .../Bundle/Resources/config/graphql.xml | 1 + .../Factory/CollectionResolverFactory.php | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml index ad4f2b7ab05..a6e6441d65f 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml @@ -18,6 +18,7 @@ %api_platform.collection.pagination.enabled% + diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index d1a6bcc7ea1..abed51f57fc 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -17,6 +17,10 @@ use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; use ApiPlatform\Core\DataProvider\PaginatorInterface; use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; +use ApiPlatform\Core\Event\PostReadEvent; +use ApiPlatform\Core\Event\PostSerializeEvent; +use ApiPlatform\Core\Event\PreReadEvent; +use ApiPlatform\Core\Event\PreSerializeEvent; use ApiPlatform\Core\Exception\ResourceClassNotSupportedException; use ApiPlatform\Core\GraphQl\Resolver\FieldsToAttributesTrait; use ApiPlatform\Core\GraphQl\Resolver\ResourceAccessCheckerTrait; @@ -25,6 +29,7 @@ use ApiPlatform\Core\Security\ResourceAccessCheckerInterface; use GraphQL\Error\Error; use GraphQL\Type\Definition\ResolveInfo; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -49,8 +54,12 @@ final class CollectionResolverFactory implements ResolverFactoryInterface private $requestStack; private $paginationEnabled; private $resourceMetadataFactory; + /** + * @var EventDispatcherInterface + */ + private $dispatcher; - public function __construct(CollectionDataProviderInterface $collectionDataProvider, SubresourceDataProviderInterface $subresourceDataProvider, NormalizerInterface $normalizer, IdentifiersExtractorInterface $identifiersExtractor, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, RequestStack $requestStack = null, bool $paginationEnabled = false) + public function __construct(CollectionDataProviderInterface $collectionDataProvider, SubresourceDataProviderInterface $subresourceDataProvider, NormalizerInterface $normalizer, IdentifiersExtractorInterface $identifiersExtractor, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, RequestStack $requestStack = null, bool $paginationEnabled = false, EventDispatcherInterface $dispatcher = null) { $this->subresourceDataProvider = $subresourceDataProvider; $this->collectionDataProvider = $collectionDataProvider; @@ -60,6 +69,7 @@ public function __construct(CollectionDataProviderInterface $collectionDataProvi $this->requestStack = $requestStack; $this->paginationEnabled = $paginationEnabled; $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->dispatcher = $dispatcher; } public function __invoke(string $resourceClass = null, string $rootClass = null, string $operationName = null): callable @@ -85,17 +95,38 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, if (isset($rootClass, $source[$rootProperty = $info->fieldName], $source[ItemNormalizer::ITEM_KEY])) { $rootResolvedFields = $this->identifiersExtractor->getIdentifiersFromItem(unserialize($source[ItemNormalizer::ITEM_KEY])); $subresource = $this->getSubresource($rootClass, $rootResolvedFields, array_keys($rootResolvedFields), $rootProperty, $resourceClass, true, $dataProviderContext); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($subresource)); + } + $collection = $subresource ?? []; } else { + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent([])); + } + $collection = $this->collectionDataProvider->getCollection($resourceClass, null, $dataProviderContext); } + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($collection)); + } + $this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $collection, $operationName ?? 'query'); if (!$this->paginationEnabled) { $data = []; foreach ($collection as $index => $object) { + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); + } + $data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext); + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($collection)); + } } return $data; @@ -118,10 +149,18 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, } foreach ($collection as $index => $object) { + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); + } + $data['edges'][$index] = [ 'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext), 'cursor' => base64_encode((string) ($index + $offset)), ]; + + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($collection)); + } } return $data; From 3af67320c999a46eb8bcd8dcbe8bc173a465c116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 16 Nov 2018 16:47:16 +0100 Subject: [PATCH 18/46] Remove useless PhpDoc --- src/GraphQl/Resolver/Factory/CollectionResolverFactory.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index abed51f57fc..03acf0410da 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -54,9 +54,6 @@ final class CollectionResolverFactory implements ResolverFactoryInterface private $requestStack; private $paginationEnabled; private $resourceMetadataFactory; - /** - * @var EventDispatcherInterface - */ private $dispatcher; public function __construct(CollectionDataProviderInterface $collectionDataProvider, SubresourceDataProviderInterface $subresourceDataProvider, NormalizerInterface $normalizer, IdentifiersExtractorInterface $identifiersExtractor, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourceAccessCheckerInterface $resourceAccessChecker = null, RequestStack $requestStack = null, bool $paginationEnabled = false, EventDispatcherInterface $dispatcher = null) From e037b11da60c1c9bd8d2666840be81ad7727173e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Mon, 19 Nov 2018 09:20:08 +0100 Subject: [PATCH 19/46] Sending serialized data instead of the data themselves in the PostSerializeEvent --- src/EventListener/SerializeListener.php | 6 ++++-- src/GraphQl/Resolver/Factory/CollectionResolverFactory.php | 4 ++-- src/GraphQl/Resolver/ItemResolver.php | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index bcb090cfea7..098247d6399 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -80,12 +80,14 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($controllerResult)); } - $event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context)); + $serializedResult = $this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($controllerResult)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($serializedResult)); } + $event->setControllerResult($serializedResult); + $request->attributes->set('_api_respond', true); $request->attributes->set('_resources', $request->attributes->get('_resources', []) + (array) $resources); } diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index 03acf0410da..511957301c5 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -122,7 +122,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($collection)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data[$index])); } } @@ -156,7 +156,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, ]; if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($collection)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data['edges'][$index])); } } diff --git a/src/GraphQl/Resolver/ItemResolver.php b/src/GraphQl/Resolver/ItemResolver.php index 74ecfb3c2ef..1cabf8d44ed 100644 --- a/src/GraphQl/Resolver/ItemResolver.php +++ b/src/GraphQl/Resolver/ItemResolver.php @@ -95,7 +95,7 @@ public function __invoke($source, $args, $context, ResolveInfo $info) $normalizedObject = $this->normalizer->normalize($item, ItemNormalizer::FORMAT, $normalizationContext + $baseNormalizationContext); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($item)); + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($normalizedObject)); } return $normalizedObject; From 8ec73fd7e172f53b44b67b0e08c9d4ec716d7999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Tue, 20 Nov 2018 10:23:05 +0100 Subject: [PATCH 20/46] Fix the position of the dispatch --- src/GraphQl/Resolver/Factory/CollectionResolverFactory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index 511957301c5..8b508e973bc 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -91,12 +91,12 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, if (isset($rootClass, $source[$rootProperty = $info->fieldName], $source[ItemNormalizer::ITEM_KEY])) { $rootResolvedFields = $this->identifiersExtractor->getIdentifiersFromItem(unserialize($source[ItemNormalizer::ITEM_KEY])); - $subresource = $this->getSubresource($rootClass, $rootResolvedFields, array_keys($rootResolvedFields), $rootProperty, $resourceClass, true, $dataProviderContext); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($subresource)); + $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($rootResolvedFields)); } + $subresource = $this->getSubresource($rootClass, $rootResolvedFields, array_keys($rootResolvedFields), $rootProperty, $resourceClass, true, $dataProviderContext); $collection = $subresource ?? []; } else { if (null !== $this->dispatcher) { From 18462572ff13a6654e927a82aad3b52f01017726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Tue, 20 Nov 2018 10:48:41 +0100 Subject: [PATCH 21/46] Dispatching outside the loops --- .../Factory/CollectionResolverFactory.php | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index 8b508e973bc..b9646c25eed 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -114,16 +114,17 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, if (!$this->paginationEnabled) { $data = []; - foreach ($collection as $index => $object) { - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); - } + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); + } + + foreach ($collection as $index => $object) { $data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext); + } - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data[$index])); - } + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data)); } return $data; @@ -145,19 +146,19 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $data['totalCount'] = $totalItems; } - foreach ($collection as $index => $object) { - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); - } + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($collection)); + } + foreach ($collection as $index => $object) { $data['edges'][$index] = [ 'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext), 'cursor' => base64_encode((string) ($index + $offset)), ]; + } - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data['edges'][$index])); - } + if (null !== $this->dispatcher) { + $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($data['edges'])); } return $data; From fe8596c270fa505da9474ad5b5d64021e0c85cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 14:04:57 +0100 Subject: [PATCH 22/46] Rename ApiPlatformEvents class to Events --- .../{ApiPlatformEvents.php => Events.php} | 2 +- src/Event/PostAddFormatEvent.php | 2 +- src/Event/PostDeserializeEvent.php | 2 +- src/Event/PostReadEvent.php | 2 +- src/Event/PostRespondEvent.php | 2 +- src/Event/PostSerializeEvent.php | 2 +- src/Event/PostWriteEvent.php | 2 +- src/Event/PreAddFormatEvent.php | 2 +- src/Event/PreDeserializeEvent.php | 2 +- src/Event/PreReadEvent.php | 2 +- src/Event/PreRespondEvent.php | 2 +- src/Event/PreSerializeEvent.php | 2 +- src/Event/PreWriteEvent.php | 2 +- tests/EventListener/AddFormatListenerTest.php | 110 +++++++----------- 14 files changed, 56 insertions(+), 80 deletions(-) rename src/Event/{ApiPlatformEvents.php => Events.php} (96%) diff --git a/src/Event/ApiPlatformEvents.php b/src/Event/Events.php similarity index 96% rename from src/Event/ApiPlatformEvents.php rename to src/Event/Events.php index 9f48c0d3729..8349dcef632 100644 --- a/src/Event/ApiPlatformEvents.php +++ b/src/Event/Events.php @@ -13,7 +13,7 @@ namespace ApiPlatform\Core\Event; -final class ApiPlatformEvents +final class Events { const PRE_READ = 'api_platform.pre_read'; const POST_READ = 'api_platform.post_read'; diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php index e7c369968ed..a487709ee7b 100644 --- a/src/Event/PostAddFormatEvent.php +++ b/src/Event/PostAddFormatEvent.php @@ -17,7 +17,7 @@ class PostAddFormatEvent extends Event { - const NAME = ApiPlatformEvents::POST_ADD_FORMAT; + const NAME = Events::POST_ADD_FORMAT; private $formats; public function __construct($formats) diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php index 5a9f4b562a9..70ef176426e 100644 --- a/src/Event/PostDeserializeEvent.php +++ b/src/Event/PostDeserializeEvent.php @@ -17,7 +17,7 @@ final class PostDeserializeEvent extends Event { - const NAME = ApiPlatformEvents::POST_DESERIALIZE; + const NAME = Events::POST_DESERIALIZE; private $controllerResult; public function __construct($controllerResult) diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index 28767f6dcb1..cd99f5d2e42 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -17,7 +17,7 @@ final class PostReadEvent extends Event { - const NAME = ApiPlatformEvents::POST_READ; + const NAME = Events::POST_READ; private $data; diff --git a/src/Event/PostRespondEvent.php b/src/Event/PostRespondEvent.php index a9985b71830..78e9ed522fc 100644 --- a/src/Event/PostRespondEvent.php +++ b/src/Event/PostRespondEvent.php @@ -18,7 +18,7 @@ final class PostRespondEvent extends Event { - const NAME = ApiPlatformEvents::POST_RESPOND; + const NAME = Events::POST_RESPOND; private $event; diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index 5dc1fee4f02..90198b58485 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -17,7 +17,7 @@ final class PostSerializeEvent extends Event { - const NAME = ApiPlatformEvents::POST_SERIALIZE; + const NAME = Events::POST_SERIALIZE; private $object; public function __construct($object) diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index a0baf1bc1ec..d7d169a8a08 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -17,7 +17,7 @@ class PostWriteEvent extends Event { - const NAME = ApiPlatformEvents::POST_WRITE; + const NAME = Events::POST_WRITE; private $method; private $controllerResult; diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php index f846d08cae4..a5237c494ec 100644 --- a/src/Event/PreAddFormatEvent.php +++ b/src/Event/PreAddFormatEvent.php @@ -17,7 +17,7 @@ class PreAddFormatEvent extends Event { - const NAME = ApiPlatformEvents::PRE_ADD_FORMAT; + const NAME = Events::PRE_ADD_FORMAT; private $formats; public function __construct($formats) diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index c053de72002..85304c0f3e5 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -17,7 +17,7 @@ final class PreDeserializeEvent extends Event { - const NAME = ApiPlatformEvents::PRE_DESERIALIZE; + const NAME = Events::PRE_DESERIALIZE; private $controllerResult; public function __construct($controllerResult) diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index 07ea4c9f9e6..c8b73590439 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -17,7 +17,7 @@ final class PreReadEvent extends Event { - const NAME = ApiPlatformEvents::PRE_READ; + const NAME = Events::PRE_READ; private $data; diff --git a/src/Event/PreRespondEvent.php b/src/Event/PreRespondEvent.php index d5d2637ed91..204d14c1d26 100644 --- a/src/Event/PreRespondEvent.php +++ b/src/Event/PreRespondEvent.php @@ -18,7 +18,7 @@ final class PreRespondEvent extends Event { - const NAME = ApiPlatformEvents::PRE_RESPOND; + const NAME = Events::PRE_RESPOND; private $event; diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index 78bb57f3eb1..0d82e7996ab 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -17,7 +17,7 @@ final class PreSerializeEvent extends Event { - const NAME = ApiPlatformEvents::PRE_SERIALIZE; + const NAME = Events::PRE_SERIALIZE; private $object; public function __construct($object) diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index fc7f16a3548..08490c8c587 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -17,7 +17,7 @@ class PreWriteEvent extends Event { - const NAME = ApiPlatformEvents::PRE_WRITE; + const NAME = Events::PRE_WRITE; private $method; private $controllerResult; diff --git a/tests/EventListener/AddFormatListenerTest.php b/tests/EventListener/AddFormatListenerTest.php index 61da5fa819d..a92a10310c0 100644 --- a/tests/EventListener/AddFormatListenerTest.php +++ b/tests/EventListener/AddFormatListenerTest.php @@ -14,10 +14,12 @@ namespace ApiPlatform\Core\Tests\EventListener; use ApiPlatform\Core\Api\FormatsProviderInterface; +use ApiPlatform\Core\Event\PostAddFormatEvent; +use ApiPlatform\Core\Event\PreAddFormatEvent; use ApiPlatform\Core\EventListener\AddFormatListener; use Negotiation\Negotiator; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; @@ -33,28 +35,29 @@ public function testNoResourceClass() $request = new Request(); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); + $formatsProviderProphecy->getFormatsFromAttributes()->shouldNotBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); - $this->assertNull($request->getRequestFormat(null)); + $this->assertNull($request->getFormat('application/vnd.notexist')); } public function testSupportedRequestFormat() { - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->setRequestFormat('xml'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['xml' => ['text/xml']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['xml' => ['text/xml']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -69,11 +72,11 @@ public function testRespondFlag() $request->setRequestFormat('xml'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['xml' => ['text/xml']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['xml' => ['text/xml']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -87,15 +90,14 @@ public function testUnsupportedRequestFormat() $this->expectException(NotAcceptableHttpException::class); $this->expectExceptionMessage('Requested format "text/xml" is not supported. Supported MIME types are "application/json".'); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->setRequestFormat('xml'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); - $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -105,15 +107,15 @@ public function testUnsupportedRequestFormat() public function testSupportedAcceptHeader() { - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->headers->set('Accept', 'text/html, application/xhtml+xml, application/xml, application/json;q=0.9, */*;q=0.8'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -121,35 +123,17 @@ public function testSupportedAcceptHeader() $this->assertSame('json', $request->getRequestFormat()); } - public function testSupportedAcceptHeaderSymfonyBuiltInFormat() - { - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); - $request->headers->set('Accept', 'application/json'); - - $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); - $event = $eventProphecy->reveal(); - - $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['jsonld' => ['application/ld+json', 'application/json']]); - - $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); - $listener->onKernelRequest($event); - - $this->assertSame('jsonld', $request->getRequestFormat()); - } - public function testAcceptAllHeader() { - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->headers->set('Accept', 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -163,34 +147,15 @@ public function testUnsupportedAcceptHeader() $this->expectException(NotAcceptableHttpException::class); $this->expectExceptionMessage('Requested format "text/html, application/xhtml+xml, application/xml;q=0.9" is not supported. Supported MIME types are "application/octet-stream", "application/json".'); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->headers->set('Accept', 'text/html, application/xhtml+xml, application/xml;q=0.9'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); - $event = $eventProphecy->reveal(); - - $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']]); - - $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); - $listener->onKernelRequest($event); - } - - public function testUnsupportedAcceptHeaderSymfonyBuiltInFormat() - { - $this->expectException(NotAcceptableHttpException::class); - $this->expectExceptionMessage('Requested format "text/xml" is not supported. Supported MIME types are "application/json".'); - - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); - $request->headers->set('Accept', 'text/xml'); - - $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['binary' => ['application/octet-stream'], 'json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -201,15 +166,15 @@ public function testInvalidAcceptHeader() $this->expectException(NotAcceptableHttpException::class); $this->expectExceptionMessage('Requested format "invalid" is not supported. Supported MIME types are "application/json".'); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->headers->set('Accept', 'invalid'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -217,16 +182,16 @@ public function testInvalidAcceptHeader() public function testAcceptHeaderTakePrecedenceOverRequestFormat() { - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request = new Request([], [], ['_api_resource_class' => 'Foo']); $request->headers->set('Accept', 'application/json'); $request->setRequestFormat('xml'); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['xml' => ['application/xml'], 'json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['xml' => ['application/xml'], 'json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -239,14 +204,14 @@ public function testInvalidRouteFormat() $this->expectException(NotFoundHttpException::class); $this->expectExceptionMessage('Format "invalid" is not supported'); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get', '_format' => 'invalid']); + $request = new Request([], [], ['_api_resource_class' => 'Foo', '_format' => 'invalid']); $eventProphecy = $this->prophesize(GetResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request); + $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $event = $eventProphecy->reveal(); $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); - $formatsProviderProphecy->getFormatsFromAttributes(Argument::any())->willReturn(['json' => ['application/json']]); + $formatsProviderProphecy->getFormatsFromAttributes([])->willReturn(['json' => ['application/json']])->shouldBeCalled(); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); @@ -264,6 +229,17 @@ public function testResourceClassSupportedRequestFormat() $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); $formatsProviderProphecy->getFormatsFromAttributes(['resource_class' => 'Foo', 'input_class' => 'Foo', 'output_class' => 'Foo', 'collection_operation_name' => 'get', 'receive' => true, 'persist' => true])->willReturn(['csv' => ['text/csv']])->shouldBeCalled(); + $preAddFormatEvent = $this->prophesize(PreAddFormatEvent::class); + $preAddFormatEvent->willBeConstructedWith(['application/json']); + + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventDispatcher->dispatch($preAddFormatEvent)->shouldBeCalled(self::once()); + + $postAddFormatEvent = $this->prophesize(PostAddFormatEvent::class); + $postAddFormatEvent->willBeConstructedWith(['application/json']); + + $eventDispatcher->dispatch($postAddFormatEvent)->shouldBeCalled(self::once()); + $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); From 0895641daabf2bc9b011f70cc4e265b5e97f40a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 14:11:41 +0100 Subject: [PATCH 23/46] Remove pre-, post- add and respond events based on @dunglas' proposition --- src/Event/PostRespondEvent.php | 39 --------------------------- src/Event/PreRespondEvent.php | 39 --------------------------- src/EventListener/RespondListener.php | 16 +---------- 3 files changed, 1 insertion(+), 93 deletions(-) delete mode 100644 src/Event/PostRespondEvent.php delete mode 100644 src/Event/PreRespondEvent.php diff --git a/src/Event/PostRespondEvent.php b/src/Event/PostRespondEvent.php deleted file mode 100644 index 78e9ed522fc..00000000000 --- a/src/Event/PostRespondEvent.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * 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\Core\Event; - -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; - -final class PostRespondEvent extends Event -{ - const NAME = Events::POST_RESPOND; - - private $event; - - public function __construct(GetResponseForControllerResultEvent $event) - { - $this->event = $event; - } - - public function getEvent(): GetResponseForControllerResultEvent - { - return $this->event; - } - - public function setEvent(GetResponseForControllerResultEvent $event): void - { - $this->event = $event; - } -} diff --git a/src/Event/PreRespondEvent.php b/src/Event/PreRespondEvent.php deleted file mode 100644 index 204d14c1d26..00000000000 --- a/src/Event/PreRespondEvent.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * 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\Core\Event; - -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; - -final class PreRespondEvent extends Event -{ - const NAME = Events::PRE_RESPOND; - - private $event; - - public function __construct(GetResponseForControllerResultEvent $event) - { - $this->event = $event; - } - - public function getEvent(): GetResponseForControllerResultEvent - { - return $this->event; - } - - public function setEvent(GetResponseForControllerResultEvent $event): void - { - $this->event = $event; - } -} diff --git a/src/EventListener/RespondListener.php b/src/EventListener/RespondListener.php index 9546ce7e162..d78844c2b1f 100644 --- a/src/EventListener/RespondListener.php +++ b/src/EventListener/RespondListener.php @@ -13,11 +13,8 @@ namespace ApiPlatform\Core\EventListener; -use ApiPlatform\Core\Event\PostRespondEvent; -use ApiPlatform\Core\Event\PreRespondEvent; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -34,13 +31,10 @@ final class RespondListener ]; private $resourceMetadataFactory; - /** @var EventDispatcherInterface */ - private $dispatcher; - public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null, EventDispatcherInterface $dispatcher = null) + public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory = null) { $this->resourceMetadataFactory = $resourceMetadataFactory; - $this->dispatcher = $dispatcher; } /** @@ -81,18 +75,10 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $status = $resourceMetadata->getOperationAttribute($attributes, 'status'); } - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreRespondEvent::NAME, new PreRespondEvent($event)); - } - $event->setResponse(new Response( $controllerResult, $status ?? self::METHOD_TO_CODE[$request->getMethod()] ?? Response::HTTP_OK, $headers )); - - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostRespondEvent::NAME, new PostRespondEvent($event)); - } } } From c0b1ca73172e026973b9da72bfb512505f93573a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 14:46:03 +0100 Subject: [PATCH 24/46] Fix various issues after @dunglas' review --- src/Event/PostAddFormatEvent.php | 8 ++++---- src/Event/PostDeserializeEvent.php | 12 ++++++------ src/Event/PostReadEvent.php | 1 - src/Event/PostSerializeEvent.php | 12 ++++++------ src/Event/PostWriteEvent.php | 28 ++++++++-------------------- src/Event/PreAddFormatEvent.php | 8 ++++---- src/Event/PreDeserializeEvent.php | 12 ++++++------ src/Event/PreReadEvent.php | 1 - src/Event/PreSerializeEvent.php | 12 ++++++------ src/Event/PreWriteEvent.php | 2 +- 10 files changed, 41 insertions(+), 55 deletions(-) diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php index a487709ee7b..30aea6bca13 100644 --- a/src/Event/PostAddFormatEvent.php +++ b/src/Event/PostAddFormatEvent.php @@ -15,22 +15,22 @@ use Symfony\Component\EventDispatcher\Event; -class PostAddFormatEvent extends Event +final class PostAddFormatEvent extends Event { const NAME = Events::POST_ADD_FORMAT; private $formats; - public function __construct($formats) + public function __construct(array $formats) { $this->formats = $formats; } - public function getFormats() + public function getFormats(): array { return $this->formats; } - public function setFormats($formats): void + public function setFormats(array $formats): void { $this->formats = $formats; } diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php index 70ef176426e..8cf257f8107 100644 --- a/src/Event/PostDeserializeEvent.php +++ b/src/Event/PostDeserializeEvent.php @@ -18,20 +18,20 @@ final class PostDeserializeEvent extends Event { const NAME = Events::POST_DESERIALIZE; - private $controllerResult; + private $data; public function __construct($controllerResult) { - $this->controllerResult = $controllerResult; + $this->data = $controllerResult; } - public function getControllerResult() + public function getData() { - return $this->controllerResult; + return $this->data; } - public function setControllerResult($controllerResult): void + public function setData($data): void { - $this->controllerResult = $controllerResult; + $this->data = $data; } } diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index cd99f5d2e42..b4330f9630e 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -18,7 +18,6 @@ final class PostReadEvent extends Event { const NAME = Events::POST_READ; - private $data; public function __construct($data) diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index 90198b58485..d6686604cd5 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -18,20 +18,20 @@ final class PostSerializeEvent extends Event { const NAME = Events::POST_SERIALIZE; - private $object; + private $data; public function __construct($object) { - $this->object = $object; + $this->data = $object; } - public function getObject() + public function getData() { - return $this->object; + return $this->data; } - public function setObject($object): void + public function setData($data): void { - $this->object = $object; + $this->data = $data; } } diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index d7d169a8a08..77d851b0640 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -15,35 +15,23 @@ use Symfony\Component\EventDispatcher\Event; -class PostWriteEvent extends Event +final class PostWriteEvent extends Event { const NAME = Events::POST_WRITE; - private $method; - private $controllerResult; + private $data; - public function __construct(string $method, $controllerResult) + public function __construct($controllerResult) { - $this->method = $method; - $this->controllerResult = $controllerResult; + $this->data = $controllerResult; } - public function getMethod(): string + public function getData() { - return $this->method; + return $this->data; } - public function setMethod(string $method): void + public function setData($data): void { - $this->method = $method; - } - - public function getControllerResult() - { - return $this->controllerResult; - } - - public function setControllerResult($controllerResult): void - { - $this->controllerResult = $controllerResult; + $this->data = $data; } } diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php index a5237c494ec..0c38ba1e28a 100644 --- a/src/Event/PreAddFormatEvent.php +++ b/src/Event/PreAddFormatEvent.php @@ -15,22 +15,22 @@ use Symfony\Component\EventDispatcher\Event; -class PreAddFormatEvent extends Event +final class PreAddFormatEvent extends Event { const NAME = Events::PRE_ADD_FORMAT; private $formats; - public function __construct($formats) + public function __construct(array $formats) { $this->formats = $formats; } - public function getFormats() + public function getFormats(): array { return $this->formats; } - public function setFormats($formats): void + public function setFormats(array $formats): void { $this->formats = $formats; } diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index 85304c0f3e5..f9eaa12ca38 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -18,20 +18,20 @@ final class PreDeserializeEvent extends Event { const NAME = Events::PRE_DESERIALIZE; - private $controllerResult; + private $data; public function __construct($controllerResult) { - $this->controllerResult = $controllerResult; + $this->data = $controllerResult; } - public function getControllerResult() + public function getData() { - return $this->controllerResult; + return $this->data; } - public function setControllerResult($controllerResult): void + public function setData($data): void { - $this->controllerResult = $controllerResult; + $this->data = $data; } } diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index c8b73590439..9806fe38770 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -18,7 +18,6 @@ final class PreReadEvent extends Event { const NAME = Events::PRE_READ; - private $data; public function __construct($data) diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index 0d82e7996ab..65113a8042d 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -18,20 +18,20 @@ final class PreSerializeEvent extends Event { const NAME = Events::PRE_SERIALIZE; - private $object; + private $data; public function __construct($object) { - $this->object = $object; + $this->data = $object; } - public function getObject() + public function getData() { - return $this->object; + return $this->data; } - public function setObject($object): void + public function setData($data): void { - $this->object = $object; + $this->data = $data; } } diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index 08490c8c587..a7c4298ab0e 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -15,7 +15,7 @@ use Symfony\Component\EventDispatcher\Event; -class PreWriteEvent extends Event +final class PreWriteEvent extends Event { const NAME = Events::PRE_WRITE; private $method; From 5e98b01c320d6179a55099b55b6bb4c58d1db8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 14:49:40 +0100 Subject: [PATCH 25/46] Allow symfony/event-dispatcher v3.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c4e92042c7d..3e09e28567d 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "doctrine/inflector": "^1.0", "psr/cache": "^1.0", "psr/container": "^1.0", - "symfony/event-dispatcher": "^4.1", + "symfony/event-dispatcher": "^3.4 || ^4.0", "symfony/http-foundation": "^3.1 || ^4.0", "symfony/http-kernel": "^2.7 || ^3.0 || ^4.0", "symfony/property-access": "^2.7 || ^3.0 || ^4.0", From a6fad0a86543052b25fe8eff8c7f99a83674f70c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 14:52:26 +0100 Subject: [PATCH 26/46] Remove $method field and rename $controllerResult to $data --- src/Event/PreWriteEvent.php | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index a7c4298ab0e..7254d6bf183 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -18,32 +18,20 @@ final class PreWriteEvent extends Event { const NAME = Events::PRE_WRITE; - private $method; - private $controllerResult; + private $data; - public function __construct(string $method, $controllerResult) + public function __construct($data) { - $this->method = $method; - $this->controllerResult = $controllerResult; + $this->data = $data; } - public function getMethod(): string + public function getData() { - return $this->method; + return $this->data; } - public function setMethod(string $method): void + public function setData($data): void { - $this->method = $method; - } - - public function getControllerResult() - { - return $this->controllerResult; - } - - public function setControllerResult($controllerResult): void - { - $this->controllerResult = $controllerResult; + $this->data = $data; } } From b2ad96b4058f29128e38d8fe575fa2334adac694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 15:35:48 +0100 Subject: [PATCH 27/46] Fix call to PreWriteEvent constructor --- src/EventListener/WriteListener.php | 6 +++--- .../Resolver/Factory/ItemMutationResolverFactory.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index af5f9899c33..c9530b62de1 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -55,7 +55,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) } if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($request->getMethod(), $controllerResult)); + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($controllerResult)); } switch ($request->getMethod()) { @@ -65,7 +65,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $persistResult = $this->dataPersister->persist($controllerResult); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($controllerResult)); } if (null === $persistResult) { @@ -85,7 +85,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $this->dataPersister->remove($controllerResult); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($request->getMethod(), $controllerResult)); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($controllerResult)); } $event->setControllerResult(null); diff --git a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php index 1c473682385..fb170f3507b 100644 --- a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php @@ -111,13 +111,13 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $this->validate($item, $info, $resourceMetadata, $operationName); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($operationName, $item)); + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($item)); } $persistResult = $this->dataPersister->persist($item); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($operationName, $item)); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($item)); } if (null === $persistResult) { @@ -127,7 +127,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, return $this->normalizer->normalize($persistResult ?? $item, ItemNormalizer::FORMAT, $normalizationContext) + $data; case 'delete': if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($operationName, $item)); + $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($item)); } if ($item) { @@ -138,7 +138,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, } if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($operationName, $item)); + $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($item)); } } From e956c62a34a676bd0ce359e110d6e48b745c8820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 16:17:51 +0100 Subject: [PATCH 28/46] Fix unit test --- tests/EventListener/AddFormatListenerTest.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/EventListener/AddFormatListenerTest.php b/tests/EventListener/AddFormatListenerTest.php index a92a10310c0..d7f5add0f4d 100644 --- a/tests/EventListener/AddFormatListenerTest.php +++ b/tests/EventListener/AddFormatListenerTest.php @@ -229,18 +229,11 @@ public function testResourceClassSupportedRequestFormat() $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); $formatsProviderProphecy->getFormatsFromAttributes(['resource_class' => 'Foo', 'input_class' => 'Foo', 'output_class' => 'Foo', 'collection_operation_name' => 'get', 'receive' => true, 'persist' => true])->willReturn(['csv' => ['text/csv']])->shouldBeCalled(); - $preAddFormatEvent = $this->prophesize(PreAddFormatEvent::class); - $preAddFormatEvent->willBeConstructedWith(['application/json']); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch($preAddFormatEvent)->shouldBeCalled(self::once()); - - $postAddFormatEvent = $this->prophesize(PostAddFormatEvent::class); - $postAddFormatEvent->willBeConstructedWith(['application/json']); + $eventDispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch($postAddFormatEvent)->shouldBeCalled(self::once()); - - $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); + $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($event); $this->assertSame('csv', $request->getRequestFormat()); From 38c2b18cea2a35c0a6b179d286d53e69f922e53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 5 Dec 2018 16:30:55 +0100 Subject: [PATCH 29/46] Fix constructor argument name --- src/Event/PreDeserializeEvent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index f9eaa12ca38..c5102a8ada1 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -20,9 +20,9 @@ final class PreDeserializeEvent extends Event const NAME = Events::PRE_DESERIALIZE; private $data; - public function __construct($controllerResult) + public function __construct($data) { - $this->data = $controllerResult; + $this->data = $data; } public function getData() From 7f28f090b485e7da8b2ef8160cfb5cb6aafb1053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 6 Dec 2018 16:52:45 +0100 Subject: [PATCH 30/46] Add unit tests for Deserialize and Read events --- tests/EventListener/DeserializeListenerTest.php | 9 ++++++++- tests/EventListener/ReadListenerTest.php | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/EventListener/DeserializeListenerTest.php b/tests/EventListener/DeserializeListenerTest.php index de32a3a6991..77e5c7a7a4d 100644 --- a/tests/EventListener/DeserializeListenerTest.php +++ b/tests/EventListener/DeserializeListenerTest.php @@ -14,10 +14,13 @@ namespace ApiPlatform\Core\Tests\EventListener; use ApiPlatform\Core\Api\FormatsProviderInterface; +use ApiPlatform\Core\Event\PostDeserializeEvent; +use ApiPlatform\Core\Event\PreDeserializeEvent; use ApiPlatform\Core\EventListener\DeserializeListener; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; @@ -168,7 +171,11 @@ public function testDeserialize(string $method, bool $populateObject) $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->willReturn([])->shouldBeCalled(); - $listener = new DeserializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $formatsProviderProphecy->reveal()); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventDispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); + + $listener = new DeserializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $formatsProviderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($eventProphecy->reveal()); } diff --git a/tests/EventListener/ReadListenerTest.php b/tests/EventListener/ReadListenerTest.php index e259bf70010..b0e469a0a9d 100644 --- a/tests/EventListener/ReadListenerTest.php +++ b/tests/EventListener/ReadListenerTest.php @@ -16,12 +16,15 @@ use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; +use ApiPlatform\Core\Event\PostReadEvent; +use ApiPlatform\Core\Event\PreReadEvent; use ApiPlatform\Core\EventListener\ReadListener; use ApiPlatform\Core\Exception\InvalidIdentifierException; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Identifier\IdentifierConverterInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -167,7 +170,11 @@ public function testRetrieveItem() $event = $this->prophesize(GetResponseEvent::class); $event->getRequest()->willReturn($request)->shouldBeCalled(); - $listener = new ReadListener($collectionDataProvider->reveal(), $itemDataProvider->reveal(), $subresourceDataProvider->reveal(), null, $identifierConverter->reveal()); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventDispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent([]))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data))->shouldBeCalled(self::once()); + + $listener = new ReadListener($collectionDataProvider->reveal(), $itemDataProvider->reveal(), $subresourceDataProvider->reveal(), null, $identifierConverter->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($event->reveal()); $this->assertSame($data, $request->attributes->get('data')); From 9bf11bd0860810355c5295c8fde1209277addcd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 11:41:36 +0100 Subject: [PATCH 31/46] Add unit tests for Serialize and Write events --- tests/EventListener/SerializeListenerTest.php | 9 ++++++++- tests/EventListener/WriteListenerTest.php | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/EventListener/SerializeListenerTest.php b/tests/EventListener/SerializeListenerTest.php index b6f43acadd7..2a2b50b0df3 100644 --- a/tests/EventListener/SerializeListenerTest.php +++ b/tests/EventListener/SerializeListenerTest.php @@ -13,11 +13,14 @@ namespace ApiPlatform\Core\Tests\EventListener; +use ApiPlatform\Core\Event\PostSerializeEvent; +use ApiPlatform\Core\Event\PreSerializeEvent; use ApiPlatform\Core\EventListener\SerializeListener; use ApiPlatform\Core\Serializer\ResourceList; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -98,7 +101,11 @@ public function testSerializeCollectionOperation() $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); - $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventDispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($eventProphecy->reveal()->getControllerResult()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent('bar'))->shouldBeCalled(self::once()); + + $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelView($eventProphecy->reveal()); } diff --git a/tests/EventListener/WriteListenerTest.php b/tests/EventListener/WriteListenerTest.php index 49fde689b04..dfd1a2083d8 100644 --- a/tests/EventListener/WriteListenerTest.php +++ b/tests/EventListener/WriteListenerTest.php @@ -15,11 +15,14 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; +use ApiPlatform\Core\Event\PostWriteEvent; +use ApiPlatform\Core\Event\PreWriteEvent; use ApiPlatform\Core\EventListener\WriteListener; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritance; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceChild; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -127,7 +130,11 @@ public function testOnKernelViewWithControllerResultAndPersistWithImmutableResou $request->setMethod($httpMethod); $request->attributes->set(sprintf('_api_%s_operation_name', 'POST' === $httpMethod ? 'collection' : 'item'), strtolower($httpMethod)); - (new WriteListener($dataPersisterProphecy->reveal(), $iriConverterProphecy->reveal()))->onKernelView($event); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventDispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); + + (new WriteListener($dataPersisterProphecy->reveal(), $iriConverterProphecy->reveal(), $eventDispatcher->reveal()))->onKernelView($event); $this->assertSame($dummy2, $event->getControllerResult()); $this->assertEquals('/dummy/1', $request->attributes->get('_api_write_item_iri')); From 9f5681b0b1d511c009b9b685989e15ff226998fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 14:13:26 +0100 Subject: [PATCH 32/46] Rename constructor argument --- src/Event/PostWriteEvent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index 77d851b0640..addac6fa6fa 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -20,9 +20,9 @@ final class PostWriteEvent extends Event const NAME = Events::POST_WRITE; private $data; - public function __construct($controllerResult) + public function __construct($data) { - $this->data = $controllerResult; + $this->data = $data; } public function getData() From 8b0a2a5803c8ada6048f2152c7f005d8c1ec9b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 14:52:10 +0100 Subject: [PATCH 33/46] Add Validate event --- src/Event/Events.php | 3 ++ src/Event/PostValidateEvent.php | 28 +++++++++++++++++++ src/Event/PreValidateEvent.php | 28 +++++++++++++++++++ .../EventListener/ValidateListener.php | 18 +++++++++++- .../EventListener/ValidateListenerTest.php | 9 +++++- 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/Event/PostValidateEvent.php create mode 100644 src/Event/PreValidateEvent.php diff --git a/src/Event/Events.php b/src/Event/Events.php index 8349dcef632..a82ee2f9014 100644 --- a/src/Event/Events.php +++ b/src/Event/Events.php @@ -32,4 +32,7 @@ final class Events const PRE_ADD_FORMAT = 'api_platform.pre_add_format'; const POST_ADD_FORMAT = 'api_platform.post_add_format'; + + const PRE_VALIDATE = 'api_platform.pre_validate'; + const POST_VALIDATE = 'api_platform.post_validate'; } diff --git a/src/Event/PostValidateEvent.php b/src/Event/PostValidateEvent.php new file mode 100644 index 00000000000..d0abc735da1 --- /dev/null +++ b/src/Event/PostValidateEvent.php @@ -0,0 +1,28 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data): void + { + $this->data = $data; + } +} diff --git a/src/Event/PreValidateEvent.php b/src/Event/PreValidateEvent.php new file mode 100644 index 00000000000..7166c1ff705 --- /dev/null +++ b/src/Event/PreValidateEvent.php @@ -0,0 +1,28 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data): void + { + $this->data = $data; + } +} diff --git a/src/Validator/EventListener/ValidateListener.php b/src/Validator/EventListener/ValidateListener.php index 5bf3afd3485..5f51c187185 100644 --- a/src/Validator/EventListener/ValidateListener.php +++ b/src/Validator/EventListener/ValidateListener.php @@ -14,9 +14,12 @@ namespace ApiPlatform\Core\Validator\EventListener; use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException; +use ApiPlatform\Core\Event\PostValidateEvent; +use ApiPlatform\Core\Event\PreValidateEvent; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; use ApiPlatform\Core\Validator\ValidatorInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; /** @@ -28,11 +31,16 @@ final class ValidateListener { private $validator; private $resourceMetadataFactory; + /** + * @var EventDispatcher + */ + private $eventDispatcher; - public function __construct(ValidatorInterface $validator, ResourceMetadataFactoryInterface $resourceMetadataFactory) + public function __construct(ValidatorInterface $validator, ResourceMetadataFactoryInterface $resourceMetadataFactory, EventDispatcher $eventDispatcher = null) { $this->validator = $validator; $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->eventDispatcher = $eventDispatcher; } /** @@ -56,6 +64,14 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']); $validationGroups = $resourceMetadata->getOperationAttribute($attributes, 'validation_groups', null, true); + if (null !== $this->eventDispatcher) { + $this->eventDispatcher->dispatch(PreValidateEvent::NAME, new PreValidateEvent($data)); + } + $this->validator->validate($data, ['groups' => $validationGroups]); + + if (null !== $this->eventDispatcher) { + $this->eventDispatcher->dispatch(PostValidateEvent::NAME, new PostValidateEvent($data)); + } } } diff --git a/tests/Validator/EventListener/ValidateListenerTest.php b/tests/Validator/EventListener/ValidateListenerTest.php index 6ed24118185..90daf697214 100644 --- a/tests/Validator/EventListener/ValidateListenerTest.php +++ b/tests/Validator/EventListener/ValidateListenerTest.php @@ -13,6 +13,8 @@ namespace ApiPlatform\Core\Tests\Validator\EventListener; +use ApiPlatform\Core\Event\PostValidateEvent; +use ApiPlatform\Core\Event\PreValidateEvent; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; use ApiPlatform\Core\Tests\Fixtures\DummyEntity; @@ -20,6 +22,7 @@ use ApiPlatform\Core\Validator\Exception\ValidationException; use ApiPlatform\Core\Validator\ValidatorInterface; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -63,7 +66,11 @@ public function testValidatorIsCalled() list($resourceMetadataFactory, $event) = $this->createEventObject($expectedValidationGroups, $data); - $validationViewListener = new ValidateListener($validator, $resourceMetadataFactory); + $eventDispatcher = $this->prophesize(EventDispatcher::class); + $eventDispatcher->dispatch(PreValidateEvent::NAME, new PreValidateEvent($data))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PostValidateEvent::NAME, new PostValidateEvent($data))->shouldBeCalled(self::once()); + + $validationViewListener = new ValidateListener($validator, $resourceMetadataFactory, $eventDispatcher->reveal()); $validationViewListener->onKernelView($event); } From 2450b8f0b5c59234b4a1455721b8037cb9709aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 15:14:42 +0100 Subject: [PATCH 34/46] Fix PHP CS --- src/Event/PostValidateEvent.php | 11 ++++++++++- src/Event/PreValidateEvent.php | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Event/PostValidateEvent.php b/src/Event/PostValidateEvent.php index d0abc735da1..928ccb44b59 100644 --- a/src/Event/PostValidateEvent.php +++ b/src/Event/PostValidateEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; diff --git a/src/Event/PreValidateEvent.php b/src/Event/PreValidateEvent.php index 7166c1ff705..16a402f4da4 100644 --- a/src/Event/PreValidateEvent.php +++ b/src/Event/PreValidateEvent.php @@ -1,8 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -namespace ApiPlatform\Core\Event; +declare(strict_types=1); +namespace ApiPlatform\Core\Event; use Symfony\Component\EventDispatcher\Event; From d435b735ecf0168bbe0b1088a3b37de8606469f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 15:50:20 +0100 Subject: [PATCH 35/46] Fix typehint error reported by SF Insight --- src/Validator/EventListener/ValidateListener.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Validator/EventListener/ValidateListener.php b/src/Validator/EventListener/ValidateListener.php index 5f51c187185..f92b9587ebf 100644 --- a/src/Validator/EventListener/ValidateListener.php +++ b/src/Validator/EventListener/ValidateListener.php @@ -19,7 +19,7 @@ use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; use ApiPlatform\Core\Validator\ValidatorInterface; -use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; /** @@ -31,12 +31,9 @@ final class ValidateListener { private $validator; private $resourceMetadataFactory; - /** - * @var EventDispatcher - */ private $eventDispatcher; - public function __construct(ValidatorInterface $validator, ResourceMetadataFactoryInterface $resourceMetadataFactory, EventDispatcher $eventDispatcher = null) + public function __construct(ValidatorInterface $validator, ResourceMetadataFactoryInterface $resourceMetadataFactory, EventDispatcherInterface $eventDispatcher = null) { $this->validator = $validator; $this->resourceMetadataFactory = $resourceMetadataFactory; From 28d1f2f6b87c4e93448a2aeac1799ffc93b89783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 7 Dec 2018 16:59:15 +0100 Subject: [PATCH 36/46] Fix PHP stan --- tests/EventListener/SerializeListenerTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/EventListener/SerializeListenerTest.php b/tests/EventListener/SerializeListenerTest.php index 2a2b50b0df3..4c2858ecb78 100644 --- a/tests/EventListener/SerializeListenerTest.php +++ b/tests/EventListener/SerializeListenerTest.php @@ -93,8 +93,10 @@ public function testSerializeCollectionOperation() $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); $request->setRequestFormat('xml'); + $data = new \stdClass(); + $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class); - $eventProphecy->getControllerResult()->willReturn(new \stdClass())->shouldBeCalled(); + $eventProphecy->getControllerResult()->willReturn($data)->shouldBeCalled(); $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $eventProphecy->setControllerResult('bar')->shouldBeCalled(); @@ -102,7 +104,7 @@ public function testSerializeCollectionOperation() $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($eventProphecy->reveal()->getControllerResult()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($data))->shouldBeCalled(self::once()); $eventDispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent('bar'))->shouldBeCalled(self::once()); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $eventDispatcher->reveal()); From 6ff432afaecc65889c03c309520af3f7a06a7ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Mon, 10 Dec 2018 09:20:07 +0100 Subject: [PATCH 37/46] Make event-dispatcher optional --- composer.json | 2 +- src/Bridge/Symfony/Bundle/Resources/config/api.xml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 3e09e28567d..e6578f2aff0 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ "doctrine/inflector": "^1.0", "psr/cache": "^1.0", "psr/container": "^1.0", - "symfony/event-dispatcher": "^3.4 || ^4.0", "symfony/http-foundation": "^3.1 || ^4.0", "symfony/http-kernel": "^2.7 || ^3.0 || ^4.0", "symfony/property-access": "^2.7 || ^3.0 || ^4.0", @@ -82,6 +81,7 @@ "ramsey/uuid": "To support Ramsey's UUID identifiers.", "symfony/cache": "To have metadata caching when using Symfony integration.", "symfony/config": "To load XML configuration files.", + "symfony/event-dispatcher": "To handle events", "symfony/expression-language": "To use authorization features.", "symfony/security": "To use authorization features.", "symfony/twig-bundle": "To use the Swagger UI integration.", diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index ba60b4aaf40..ebc4221cb66 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -139,7 +139,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -158,7 +158,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -175,14 +175,14 @@ - + - + From 25cf1af1621643d4acdb06c9254d37c7069c2da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Mon, 10 Dec 2018 09:27:49 +0100 Subject: [PATCH 38/46] Move Events class to the right namespace --- src/{Event => }/Events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/{Event => }/Events.php (96%) diff --git a/src/Event/Events.php b/src/Events.php similarity index 96% rename from src/Event/Events.php rename to src/Events.php index a82ee2f9014..36d6c2e718b 100644 --- a/src/Event/Events.php +++ b/src/Events.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace ApiPlatform\Core\Event; +namespace ApiPlatform\Core; final class Events { From b06bef186982ae3a12023b71558beba297fcc603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Mon, 10 Dec 2018 09:44:55 +0100 Subject: [PATCH 39/46] Re-order the events --- src/Events.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Events.php b/src/Events.php index 36d6c2e718b..c4eb1f0a041 100644 --- a/src/Events.php +++ b/src/Events.php @@ -18,21 +18,18 @@ final class Events const PRE_READ = 'api_platform.pre_read'; const POST_READ = 'api_platform.post_read'; + const PRE_DESERIALIZE = 'api_platform.pre_deserialize'; + const POST_DESERIALIZE = 'api_platform.post_deserialize'; + + const PRE_VALIDATE = 'api_platform.pre_validate'; + const POST_VALIDATE = 'api_platform.post_validate'; + const PRE_WRITE = 'api_platform.pre_write'; const POST_WRITE = 'api_platform.post_write'; const PRE_SERIALIZE = 'api_platform.pre_serialize'; const POST_SERIALIZE = 'api_platform.post_serialize'; - const PRE_DESERIALIZE = 'api_platform.pre_deserialize'; - const POST_DESERIALIZE = 'api_platform.post_deserialize'; - - const PRE_RESPOND = 'api_platform.pre_respond'; - const POST_RESPOND = 'api_platform.post_respond'; - const PRE_ADD_FORMAT = 'api_platform.pre_add_format'; const POST_ADD_FORMAT = 'api_platform.post_add_format'; - - const PRE_VALIDATE = 'api_platform.pre_validate'; - const POST_VALIDATE = 'api_platform.post_validate'; } From 6b7a434138fc8d204685b528ffdfd46de4e1b023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Mon, 10 Dec 2018 09:53:48 +0100 Subject: [PATCH 40/46] Fix missing use statements --- src/Event/PostAddFormatEvent.php | 1 + src/Event/PostDeserializeEvent.php | 1 + src/Event/PostReadEvent.php | 1 + src/Event/PostSerializeEvent.php | 1 + src/Event/PostValidateEvent.php | 1 + src/Event/PostWriteEvent.php | 1 + src/Event/PreAddFormatEvent.php | 1 + src/Event/PreDeserializeEvent.php | 1 + src/Event/PreReadEvent.php | 1 + src/Event/PreSerializeEvent.php | 1 + src/Event/PreValidateEvent.php | 1 + src/Event/PreWriteEvent.php | 1 + 12 files changed, 12 insertions(+) diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php index 30aea6bca13..0bd6a27b744 100644 --- a/src/Event/PostAddFormatEvent.php +++ b/src/Event/PostAddFormatEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostAddFormatEvent extends Event diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php index 8cf257f8107..f0e7a643b2e 100644 --- a/src/Event/PostDeserializeEvent.php +++ b/src/Event/PostDeserializeEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostDeserializeEvent extends Event diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index b4330f9630e..a9a70d8b708 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostReadEvent extends Event diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index d6686604cd5..dfcaeda80b7 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostSerializeEvent extends Event diff --git a/src/Event/PostValidateEvent.php b/src/Event/PostValidateEvent.php index 928ccb44b59..ee47f03b51d 100644 --- a/src/Event/PostValidateEvent.php +++ b/src/Event/PostValidateEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; class PostValidateEvent extends Event diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index addac6fa6fa..c4c5298cb0e 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostWriteEvent extends Event diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php index 0c38ba1e28a..35e7a158beb 100644 --- a/src/Event/PreAddFormatEvent.php +++ b/src/Event/PreAddFormatEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreAddFormatEvent extends Event diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index c5102a8ada1..54b4e265ec7 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreDeserializeEvent extends Event diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index 9806fe38770..a30a0920b10 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreReadEvent extends Event diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index 65113a8042d..95231286b32 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreSerializeEvent extends Event diff --git a/src/Event/PreValidateEvent.php b/src/Event/PreValidateEvent.php index 16a402f4da4..9e5c706d3c4 100644 --- a/src/Event/PreValidateEvent.php +++ b/src/Event/PreValidateEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; class PreValidateEvent extends Event diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index 7254d6bf183..17a7a619c36 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Event; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreWriteEvent extends Event From 5a3502804591747840ddb790eb569c7b49793d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Tue, 11 Dec 2018 11:08:27 +0100 Subject: [PATCH 41/46] Drop NAME constants in events, using the Events class' instead --- src/Event/PostAddFormatEvent.php | 2 -- src/Event/PostDeserializeEvent.php | 2 -- src/Event/PostReadEvent.php | 2 -- src/Event/PostSerializeEvent.php | 2 -- src/Event/PostValidateEvent.php | 2 -- src/Event/PostWriteEvent.php | 2 -- src/Event/PreAddFormatEvent.php | 2 -- src/Event/PreDeserializeEvent.php | 2 -- src/Event/PreReadEvent.php | 2 -- src/Event/PreSerializeEvent.php | 2 -- src/Event/PreValidateEvent.php | 2 -- src/Event/PreWriteEvent.php | 2 -- src/EventListener/AddFormatListener.php | 5 +++-- src/EventListener/DeserializeListener.php | 5 +++-- src/EventListener/ReadListener.php | 5 +++-- src/EventListener/SerializeListener.php | 5 +++-- src/EventListener/WriteListener.php | 5 +++-- src/Validator/EventListener/ValidateListener.php | 5 +++-- tests/EventListener/AddFormatListenerTest.php | 5 +++-- tests/EventListener/DeserializeListenerTest.php | 5 +++-- tests/EventListener/ReadListenerTest.php | 5 +++-- tests/EventListener/SerializeListenerTest.php | 5 +++-- tests/EventListener/WriteListenerTest.php | 5 +++-- tests/Validator/EventListener/ValidateListenerTest.php | 5 +++-- 24 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php index 0bd6a27b744..1e1a36527f5 100644 --- a/src/Event/PostAddFormatEvent.php +++ b/src/Event/PostAddFormatEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostAddFormatEvent extends Event { - const NAME = Events::POST_ADD_FORMAT; private $formats; public function __construct(array $formats) diff --git a/src/Event/PostDeserializeEvent.php b/src/Event/PostDeserializeEvent.php index f0e7a643b2e..9a85bbdb635 100644 --- a/src/Event/PostDeserializeEvent.php +++ b/src/Event/PostDeserializeEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostDeserializeEvent extends Event { - const NAME = Events::POST_DESERIALIZE; private $data; public function __construct($controllerResult) diff --git a/src/Event/PostReadEvent.php b/src/Event/PostReadEvent.php index a9a70d8b708..cf987d308f6 100644 --- a/src/Event/PostReadEvent.php +++ b/src/Event/PostReadEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostReadEvent extends Event { - const NAME = Events::POST_READ; private $data; public function __construct($data) diff --git a/src/Event/PostSerializeEvent.php b/src/Event/PostSerializeEvent.php index dfcaeda80b7..354a68557b4 100644 --- a/src/Event/PostSerializeEvent.php +++ b/src/Event/PostSerializeEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostSerializeEvent extends Event { - const NAME = Events::POST_SERIALIZE; private $data; public function __construct($object) diff --git a/src/Event/PostValidateEvent.php b/src/Event/PostValidateEvent.php index ee47f03b51d..7a9a274d375 100644 --- a/src/Event/PostValidateEvent.php +++ b/src/Event/PostValidateEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; class PostValidateEvent extends Event { - const NAME = Events::POST_VALIDATE; private $data; public function __construct($data) diff --git a/src/Event/PostWriteEvent.php b/src/Event/PostWriteEvent.php index c4c5298cb0e..914fafb5f9c 100644 --- a/src/Event/PostWriteEvent.php +++ b/src/Event/PostWriteEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PostWriteEvent extends Event { - const NAME = Events::POST_WRITE; private $data; public function __construct($data) diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php index 35e7a158beb..9397f566056 100644 --- a/src/Event/PreAddFormatEvent.php +++ b/src/Event/PreAddFormatEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreAddFormatEvent extends Event { - const NAME = Events::PRE_ADD_FORMAT; private $formats; public function __construct(array $formats) diff --git a/src/Event/PreDeserializeEvent.php b/src/Event/PreDeserializeEvent.php index 54b4e265ec7..a1df5494264 100644 --- a/src/Event/PreDeserializeEvent.php +++ b/src/Event/PreDeserializeEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreDeserializeEvent extends Event { - const NAME = Events::PRE_DESERIALIZE; private $data; public function __construct($data) diff --git a/src/Event/PreReadEvent.php b/src/Event/PreReadEvent.php index a30a0920b10..2c61685e97a 100644 --- a/src/Event/PreReadEvent.php +++ b/src/Event/PreReadEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreReadEvent extends Event { - const NAME = Events::PRE_READ; private $data; public function __construct($data) diff --git a/src/Event/PreSerializeEvent.php b/src/Event/PreSerializeEvent.php index 95231286b32..f2fcc91e3b9 100644 --- a/src/Event/PreSerializeEvent.php +++ b/src/Event/PreSerializeEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreSerializeEvent extends Event { - const NAME = Events::PRE_SERIALIZE; private $data; public function __construct($object) diff --git a/src/Event/PreValidateEvent.php b/src/Event/PreValidateEvent.php index 9e5c706d3c4..91a4be15baf 100644 --- a/src/Event/PreValidateEvent.php +++ b/src/Event/PreValidateEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; class PreValidateEvent extends Event { - const NAME = Events::PRE_VALIDATE; private $data; public function __construct($data) diff --git a/src/Event/PreWriteEvent.php b/src/Event/PreWriteEvent.php index 17a7a619c36..ad68047a0ae 100644 --- a/src/Event/PreWriteEvent.php +++ b/src/Event/PreWriteEvent.php @@ -13,12 +13,10 @@ namespace ApiPlatform\Core\Event; -use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\Event; final class PreWriteEvent extends Event { - const NAME = Events::PRE_WRITE; private $data; public function __construct($data) diff --git a/src/EventListener/AddFormatListener.php b/src/EventListener/AddFormatListener.php index 21023f0d1c7..eacb21d3f4b 100644 --- a/src/EventListener/AddFormatListener.php +++ b/src/EventListener/AddFormatListener.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Api\FormatsProviderInterface; use ApiPlatform\Core\Event\PostAddFormatEvent; use ApiPlatform\Core\Event\PreAddFormatEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Util\RequestAttributesExtractor; use Negotiation\Negotiator; @@ -79,13 +80,13 @@ public function onKernelRequest(GetResponseEvent $event) $this->populateMimeTypes(); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent($this->formats)); + $this->dispatcher->dispatch(Events::PRE_ADD_FORMAT, new PreAddFormatEvent($this->formats)); } $this->addRequestFormats($request, $this->formats); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent($this->formats)); + $this->dispatcher->dispatch(Events::POST_ADD_FORMAT, new PostAddFormatEvent($this->formats)); } // Empty strings must be converted to null because the Symfony router doesn't support parameter typing before 3.2 (_format) diff --git a/src/EventListener/DeserializeListener.php b/src/EventListener/DeserializeListener.php index 4f895f6cda6..d890b03db7d 100644 --- a/src/EventListener/DeserializeListener.php +++ b/src/EventListener/DeserializeListener.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Api\FormatsProviderInterface; use ApiPlatform\Core\Event\PostDeserializeEvent; use ApiPlatform\Core\Event\PreDeserializeEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; @@ -96,7 +97,7 @@ public function onKernelRequest(GetResponseEvent $event) } if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($requestContent)); + $this->dispatcher->dispatch(Events::PRE_DESERIALIZE, new PreDeserializeEvent($requestContent)); } $request->attributes->set( @@ -107,7 +108,7 @@ public function onKernelRequest(GetResponseEvent $event) ); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($requestContent)); + $this->dispatcher->dispatch(Events::POST_DESERIALIZE, new PostDeserializeEvent($requestContent)); } } diff --git a/src/EventListener/ReadListener.php b/src/EventListener/ReadListener.php index c51497cb64f..c685cb616e5 100644 --- a/src/EventListener/ReadListener.php +++ b/src/EventListener/ReadListener.php @@ -19,6 +19,7 @@ use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; use ApiPlatform\Core\Event\PostReadEvent; use ApiPlatform\Core\Event\PreReadEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\InvalidIdentifierException; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Identifier\IdentifierConverterInterface; @@ -95,7 +96,7 @@ public function onKernelRequest(GetResponseEvent $event) $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($data)); + $this->dispatcher->dispatch(Events::PRE_READ, new PreReadEvent($data)); } if (isset($attributes['item_operation_name'])) { @@ -113,7 +114,7 @@ public function onKernelRequest(GetResponseEvent $event) } if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data)); + $this->dispatcher->dispatch(Events::POST_READ, new PostReadEvent($data)); } if (null === $data) { diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index 098247d6399..28be933f852 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -15,6 +15,7 @@ use ApiPlatform\Core\Event\PostSerializeEvent; use ApiPlatform\Core\Event\PreSerializeEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Serializer\ResourceList; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; @@ -77,13 +78,13 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $request->attributes->set('_api_normalization_context', $context); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($controllerResult)); + $this->dispatcher->dispatch(Events::PRE_SERIALIZE, new PreSerializeEvent($controllerResult)); } $serializedResult = $this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent($serializedResult)); + $this->dispatcher->dispatch(Events::POST_SERIALIZE, new PostSerializeEvent($serializedResult)); } $event->setControllerResult($serializedResult); diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index c9530b62de1..6ec74dcbd24 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -17,6 +17,7 @@ use ApiPlatform\Core\DataPersister\DataPersisterInterface; use ApiPlatform\Core\Event\PostWriteEvent; use ApiPlatform\Core\Event\PreWriteEvent; +use ApiPlatform\Core\Events; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -55,7 +56,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) } if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($controllerResult)); + $this->dispatcher->dispatch(Events::PRE_WRITE, new PreWriteEvent($controllerResult)); } switch ($request->getMethod()) { @@ -65,7 +66,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $persistResult = $this->dataPersister->persist($controllerResult); if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($controllerResult)); + $this->dispatcher->dispatch(Events::POST_WRITE, new PostWriteEvent($controllerResult)); } if (null === $persistResult) { diff --git a/src/Validator/EventListener/ValidateListener.php b/src/Validator/EventListener/ValidateListener.php index f92b9587ebf..f6705fdd8dc 100644 --- a/src/Validator/EventListener/ValidateListener.php +++ b/src/Validator/EventListener/ValidateListener.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException; use ApiPlatform\Core\Event\PostValidateEvent; use ApiPlatform\Core\Event\PreValidateEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Util\RequestAttributesExtractor; use ApiPlatform\Core\Validator\ValidatorInterface; @@ -62,13 +63,13 @@ public function onKernelView(GetResponseForControllerResultEvent $event) $validationGroups = $resourceMetadata->getOperationAttribute($attributes, 'validation_groups', null, true); if (null !== $this->eventDispatcher) { - $this->eventDispatcher->dispatch(PreValidateEvent::NAME, new PreValidateEvent($data)); + $this->eventDispatcher->dispatch(Events::PRE_VALIDATE, new PreValidateEvent($data)); } $this->validator->validate($data, ['groups' => $validationGroups]); if (null !== $this->eventDispatcher) { - $this->eventDispatcher->dispatch(PostValidateEvent::NAME, new PostValidateEvent($data)); + $this->eventDispatcher->dispatch(Events::POST_VALIDATE, new PostValidateEvent($data)); } } } diff --git a/tests/EventListener/AddFormatListenerTest.php b/tests/EventListener/AddFormatListenerTest.php index d7f5add0f4d..729659cb9ae 100644 --- a/tests/EventListener/AddFormatListenerTest.php +++ b/tests/EventListener/AddFormatListenerTest.php @@ -17,6 +17,7 @@ use ApiPlatform\Core\Event\PostAddFormatEvent; use ApiPlatform\Core\Event\PreAddFormatEvent; use ApiPlatform\Core\EventListener\AddFormatListener; +use ApiPlatform\Core\Events; use Negotiation\Negotiator; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -230,8 +231,8 @@ public function testResourceClassSupportedRequestFormat() $formatsProviderProphecy->getFormatsFromAttributes(['resource_class' => 'Foo', 'input_class' => 'Foo', 'output_class' => 'Foo', 'collection_operation_name' => 'get', 'receive' => true, 'persist' => true])->willReturn(['csv' => ['text/csv']])->shouldBeCalled(); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreAddFormatEvent::NAME, new PreAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostAddFormatEvent::NAME, new PostAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_ADD_FORMAT, new PreAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_ADD_FORMAT, new PostAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($event); diff --git a/tests/EventListener/DeserializeListenerTest.php b/tests/EventListener/DeserializeListenerTest.php index 77e5c7a7a4d..91e02d13b36 100644 --- a/tests/EventListener/DeserializeListenerTest.php +++ b/tests/EventListener/DeserializeListenerTest.php @@ -17,6 +17,7 @@ use ApiPlatform\Core\Event\PostDeserializeEvent; use ApiPlatform\Core\Event\PreDeserializeEvent; use ApiPlatform\Core\EventListener\DeserializeListener; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -172,8 +173,8 @@ public function testDeserialize(string $method, bool $populateObject) $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->willReturn([])->shouldBeCalled(); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreDeserializeEvent::NAME, new PreDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostDeserializeEvent::NAME, new PostDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_DESERIALIZE, new PreDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_DESERIALIZE, new PostDeserializeEvent($request->getContent()))->shouldBeCalled(self::once()); $listener = new DeserializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $formatsProviderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($eventProphecy->reveal()); diff --git a/tests/EventListener/ReadListenerTest.php b/tests/EventListener/ReadListenerTest.php index b0e469a0a9d..f0767583469 100644 --- a/tests/EventListener/ReadListenerTest.php +++ b/tests/EventListener/ReadListenerTest.php @@ -19,6 +19,7 @@ use ApiPlatform\Core\Event\PostReadEvent; use ApiPlatform\Core\Event\PreReadEvent; use ApiPlatform\Core\EventListener\ReadListener; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\InvalidIdentifierException; use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Identifier\IdentifierConverterInterface; @@ -171,8 +172,8 @@ public function testRetrieveItem() $event->getRequest()->willReturn($request)->shouldBeCalled(); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent([]))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($data))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_READ, new PreReadEvent([]))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_READ, new PostReadEvent($data))->shouldBeCalled(self::once()); $listener = new ReadListener($collectionDataProvider->reveal(), $itemDataProvider->reveal(), $subresourceDataProvider->reveal(), null, $identifierConverter->reveal(), $eventDispatcher->reveal()); $listener->onKernelRequest($event->reveal()); diff --git a/tests/EventListener/SerializeListenerTest.php b/tests/EventListener/SerializeListenerTest.php index 4c2858ecb78..ae876ebfe7a 100644 --- a/tests/EventListener/SerializeListenerTest.php +++ b/tests/EventListener/SerializeListenerTest.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Event\PostSerializeEvent; use ApiPlatform\Core\Event\PreSerializeEvent; use ApiPlatform\Core\EventListener\SerializeListener; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Serializer\ResourceList; use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface; use PHPUnit\Framework\TestCase; @@ -104,8 +105,8 @@ public function testSerializeCollectionOperation() $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreSerializeEvent::NAME, new PreSerializeEvent($data))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostSerializeEvent::NAME, new PostSerializeEvent('bar'))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_SERIALIZE, new PreSerializeEvent($data))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_SERIALIZE, new PostSerializeEvent('bar'))->shouldBeCalled(self::once()); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $eventDispatcher->reveal()); $listener->onKernelView($eventProphecy->reveal()); diff --git a/tests/EventListener/WriteListenerTest.php b/tests/EventListener/WriteListenerTest.php index dfd1a2083d8..d8affb8c3e6 100644 --- a/tests/EventListener/WriteListenerTest.php +++ b/tests/EventListener/WriteListenerTest.php @@ -18,6 +18,7 @@ use ApiPlatform\Core\Event\PostWriteEvent; use ApiPlatform\Core\Event\PreWriteEvent; use ApiPlatform\Core\EventListener\WriteListener; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritance; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceChild; @@ -131,8 +132,8 @@ public function testOnKernelViewWithControllerResultAndPersistWithImmutableResou $request->attributes->set(sprintf('_api_%s_operation_name', 'POST' === $httpMethod ? 'collection' : 'item'), strtolower($httpMethod)); $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostWriteEvent::NAME, new PostWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_WRITE, new PreWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_WRITE, new PostWriteEvent($event->getControllerResult()))->shouldBeCalled(self::once()); (new WriteListener($dataPersisterProphecy->reveal(), $iriConverterProphecy->reveal(), $eventDispatcher->reveal()))->onKernelView($event); diff --git a/tests/Validator/EventListener/ValidateListenerTest.php b/tests/Validator/EventListener/ValidateListenerTest.php index 90daf697214..1b1f5ccd640 100644 --- a/tests/Validator/EventListener/ValidateListenerTest.php +++ b/tests/Validator/EventListener/ValidateListenerTest.php @@ -15,6 +15,7 @@ use ApiPlatform\Core\Event\PostValidateEvent; use ApiPlatform\Core\Event\PreValidateEvent; +use ApiPlatform\Core\Events; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; use ApiPlatform\Core\Tests\Fixtures\DummyEntity; @@ -67,8 +68,8 @@ public function testValidatorIsCalled() list($resourceMetadataFactory, $event) = $this->createEventObject($expectedValidationGroups, $data); $eventDispatcher = $this->prophesize(EventDispatcher::class); - $eventDispatcher->dispatch(PreValidateEvent::NAME, new PreValidateEvent($data))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(PostValidateEvent::NAME, new PostValidateEvent($data))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::PRE_VALIDATE, new PreValidateEvent($data))->shouldBeCalled(self::once()); + $eventDispatcher->dispatch(Events::POST_VALIDATE, new PostValidateEvent($data))->shouldBeCalled(self::once()); $validationViewListener = new ValidateListener($validator, $resourceMetadataFactory, $eventDispatcher->reveal()); $validationViewListener->onKernelView($event); From 2addb5da6fda5ba9dc43ee879be086a339af3c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Tue, 11 Dec 2018 11:13:41 +0100 Subject: [PATCH 42/46] Add missing `on-invalid` attribute on event dispatchers --- src/Bridge/Symfony/Bundle/Resources/config/graphql.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml index a6e6441d65f..d9dd6e70b61 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml @@ -18,7 +18,7 @@ %api_platform.collection.pagination.enabled% - + @@ -28,7 +28,7 @@ - + @@ -36,7 +36,7 @@ - + From 1312d3041259d7c5f8f784351be813e32637a84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Tue, 11 Dec 2018 11:48:37 +0100 Subject: [PATCH 43/46] Drop AddFormat event --- src/Event/PostAddFormatEvent.php | 36 ------------------- src/Event/PreAddFormatEvent.php | 36 ------------------- src/EventListener/AddFormatListener.php | 15 +------- src/Events.php | 3 -- tests/EventListener/AddFormatListenerTest.php | 6 +--- 5 files changed, 2 insertions(+), 94 deletions(-) delete mode 100644 src/Event/PostAddFormatEvent.php delete mode 100644 src/Event/PreAddFormatEvent.php diff --git a/src/Event/PostAddFormatEvent.php b/src/Event/PostAddFormatEvent.php deleted file mode 100644 index 1e1a36527f5..00000000000 --- a/src/Event/PostAddFormatEvent.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * 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\Core\Event; - -use Symfony\Component\EventDispatcher\Event; - -final class PostAddFormatEvent extends Event -{ - private $formats; - - public function __construct(array $formats) - { - $this->formats = $formats; - } - - public function getFormats(): array - { - return $this->formats; - } - - public function setFormats(array $formats): void - { - $this->formats = $formats; - } -} diff --git a/src/Event/PreAddFormatEvent.php b/src/Event/PreAddFormatEvent.php deleted file mode 100644 index 9397f566056..00000000000 --- a/src/Event/PreAddFormatEvent.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * 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\Core\Event; - -use Symfony\Component\EventDispatcher\Event; - -final class PreAddFormatEvent extends Event -{ - private $formats; - - public function __construct(array $formats) - { - $this->formats = $formats; - } - - public function getFormats(): array - { - return $this->formats; - } - - public function setFormats(array $formats): void - { - $this->formats = $formats; - } -} diff --git a/src/EventListener/AddFormatListener.php b/src/EventListener/AddFormatListener.php index eacb21d3f4b..8905eebe34b 100644 --- a/src/EventListener/AddFormatListener.php +++ b/src/EventListener/AddFormatListener.php @@ -14,13 +14,9 @@ namespace ApiPlatform\Core\EventListener; use ApiPlatform\Core\Api\FormatsProviderInterface; -use ApiPlatform\Core\Event\PostAddFormatEvent; -use ApiPlatform\Core\Event\PreAddFormatEvent; -use ApiPlatform\Core\Events; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Util\RequestAttributesExtractor; use Negotiation\Negotiator; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; @@ -42,7 +38,7 @@ final class AddFormatListener /** * @throws InvalidArgumentException */ - public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider, EventDispatcherInterface $dispatcher = null) + public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider) { $this->negotiator = $negotiator; if (\is_array($formatsProvider)) { @@ -56,7 +52,6 @@ public function __construct(Negotiator $negotiator, /* FormatsProviderInterface } $this->formatsProvider = $formatsProvider; - $this->dispatcher = $dispatcher; } /** @@ -79,16 +74,8 @@ public function onKernelRequest(GetResponseEvent $event) $this->populateMimeTypes(); - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(Events::PRE_ADD_FORMAT, new PreAddFormatEvent($this->formats)); - } - $this->addRequestFormats($request, $this->formats); - if (null !== $this->dispatcher) { - $this->dispatcher->dispatch(Events::POST_ADD_FORMAT, new PostAddFormatEvent($this->formats)); - } - // Empty strings must be converted to null because the Symfony router doesn't support parameter typing before 3.2 (_format) if (null === $routeFormat = $request->attributes->get('_format') ?: null) { $mimeTypes = array_keys($this->mimeTypes); diff --git a/src/Events.php b/src/Events.php index c4eb1f0a041..ff90019e914 100644 --- a/src/Events.php +++ b/src/Events.php @@ -29,7 +29,4 @@ final class Events const PRE_SERIALIZE = 'api_platform.pre_serialize'; const POST_SERIALIZE = 'api_platform.post_serialize'; - - const PRE_ADD_FORMAT = 'api_platform.pre_add_format'; - const POST_ADD_FORMAT = 'api_platform.post_add_format'; } diff --git a/tests/EventListener/AddFormatListenerTest.php b/tests/EventListener/AddFormatListenerTest.php index 729659cb9ae..b7b6cdafc0c 100644 --- a/tests/EventListener/AddFormatListenerTest.php +++ b/tests/EventListener/AddFormatListenerTest.php @@ -230,11 +230,7 @@ public function testResourceClassSupportedRequestFormat() $formatsProviderProphecy = $this->prophesize(FormatsProviderInterface::class); $formatsProviderProphecy->getFormatsFromAttributes(['resource_class' => 'Foo', 'input_class' => 'Foo', 'output_class' => 'Foo', 'collection_operation_name' => 'get', 'receive' => true, 'persist' => true])->willReturn(['csv' => ['text/csv']])->shouldBeCalled(); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventDispatcher->dispatch(Events::PRE_ADD_FORMAT, new PreAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); - $eventDispatcher->dispatch(Events::POST_ADD_FORMAT, new PostAddFormatEvent(['csv' => ['text/csv']]))->shouldBeCalled(self::once()); - - $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal(), $eventDispatcher->reveal()); + $listener = new AddFormatListener(new Negotiator(), $formatsProviderProphecy->reveal()); $listener->onKernelRequest($event); $this->assertSame('csv', $request->getRequestFormat()); From f24794e6874ff427ff93b048bb87d790d905cae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Fri, 21 Dec 2018 11:33:15 +0100 Subject: [PATCH 44/46] Fix CS --- src/EventListener/WriteListener.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EventListener/WriteListener.php b/src/EventListener/WriteListener.php index 6ec74dcbd24..8e536036d0d 100644 --- a/src/EventListener/WriteListener.php +++ b/src/EventListener/WriteListener.php @@ -18,6 +18,7 @@ use ApiPlatform\Core\Event\PostWriteEvent; use ApiPlatform\Core\Event\PreWriteEvent; use ApiPlatform\Core\Events; +use ApiPlatform\Core\Util\RequestAttributesExtractor; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; @@ -46,7 +47,7 @@ public function __construct(DataPersisterInterface $dataPersister, IriConverterI public function onKernelView(GetResponseForControllerResultEvent $event) { $request = $event->getRequest(); - if ($request->isMethodSafe(false) || !$request->attributes->has('_api_resource_class') || !$request->attributes->getBoolean('_api_persist', true)) { + if ($request->isMethodSafe(false) || !$request->attributes->getBoolean('_api_persist', true) || !$attributes = RequestAttributesExtractor::extractAttributes($request)) { return; } @@ -78,7 +79,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event) // Controller result must be immutable for _api_write_item_iri // if it's class changed compared to the base class let's avoid calling the IriConverter // especially that the Output class could be a DTO that's not referencing any route - if (null !== $this->iriConverter && \get_class($controllerResult) === \get_class($event->getControllerResult())) { + if (null !== $this->iriConverter && (false !== $attributes['output_class'] ?? null) && \get_class($controllerResult) === \get_class($event->getControllerResult())) { $request->attributes->set('_api_write_item_iri', $this->iriConverter->getIriFromItem($controllerResult)); } break; From 3fb39a1a0d3f053a14d1e5e0e3c64d7397a8c514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Thu, 3 Jan 2019 15:55:45 +0100 Subject: [PATCH 45/46] Remove useless $dispatcher variable --- src/EventListener/AddFormatListener.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EventListener/AddFormatListener.php b/src/EventListener/AddFormatListener.php index 8905eebe34b..69b512258f7 100644 --- a/src/EventListener/AddFormatListener.php +++ b/src/EventListener/AddFormatListener.php @@ -33,7 +33,6 @@ final class AddFormatListener private $formats = []; private $mimeTypes; private $formatsProvider; - private $dispatcher; /** * @throws InvalidArgumentException From 03edea2d1b4066bbe9827fb285ffa7c8a7a0d165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Deuchnord?= Date: Wed, 6 Feb 2019 15:57:28 +0100 Subject: [PATCH 46/46] Dispatch PreValidateEvent --- src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php index fb170f3507b..8c6b68a8fa3 100644 --- a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; use ApiPlatform\Core\Event\PostWriteEvent; +use ApiPlatform\Core\Event\PreValidateEvent; use ApiPlatform\Core\Event\PreWriteEvent; use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Exception\ItemNotFoundException; @@ -108,6 +109,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $context = null === $item ? ['resource_class' => $resourceClass] : ['resource_class' => $resourceClass, 'object_to_populate' => $item]; $context += $resourceMetadata->getGraphqlAttribute($operationName, 'denormalization_context', [], true); $item = $this->normalizer->denormalize($args['input'], $resourceClass, ItemNormalizer::FORMAT, $context); + $this->dispatcher->dispatch(PreValidateEvent::class, new PreValidateEvent($item)); $this->validate($item, $info, $resourceMetadata, $operationName); if (null !== $this->dispatcher) {