diff --git a/features/content_negotiation.feature b/features/content_negotiation.feature
index 84ffc8e1f7f..a174931249c 100644
--- a/features/content_negotiation.feature
+++ b/features/content_negotiation.feature
@@ -12,13 +12,51 @@ Feature: Content Negotiation support
XML!
"""
- Then the header "Content-Type" should be equal to "application/xml"
+ Then the response status code should be 201
+ And the header "Content-Type" should be equal to "application/xml"
And the response should be equal to
"""
1XML!
"""
+ Scenario: Retrieve a collection in XML
+ When I add "Accept" header equal to "text/xml"
+ And I send a "GET" request to "/dummies"
+ Then the response status code should be 200
+ And the header "Content-Type" should be equal to "text/xml; charset=UTF-8"
+ And the response should be equal to
+ """
+
+- 1XML!
+ """
+
+ Scenario: Retrieve a collection in JSON
+ When I add "Accept" header equal to "application/json"
+ And I send a "GET" request to "/dummies"
+ Then the response status code should be 200
+ And the header "Content-Type" should be equal to "application/json"
+ And the response should be in JSON
+ And the JSON should be equal to:
+ """
+[
+ {
+ "id": 1,
+ "name": "XML!",
+ "alias": null,
+ "description": null,
+ "dummyDate": null,
+ "dummyPrice": null,
+ "jsonData": [],
+ "relatedDummy": null,
+ "dummyBoolean": null,
+ "dummy": null,
+ "relatedDummies": [],
+ "nameConverted": null
+ }
+]
+ """
+
@dropSchema
Scenario: Requesting an unknown format should return JSON-LD
When I add "Accept" header equal to "text/plain"
diff --git a/features/doctrine/boolean-filter.feature b/features/doctrine/boolean_filter.feature
similarity index 100%
rename from features/doctrine/boolean-filter.feature
rename to features/doctrine/boolean_filter.feature
diff --git a/features/doctrine/date-filter.feature b/features/doctrine/date_filter.feature
similarity index 100%
rename from features/doctrine/date-filter.feature
rename to features/doctrine/date_filter.feature
diff --git a/features/doctrine/numeric-filter.feature b/features/doctrine/numeric_filter.feature
similarity index 100%
rename from features/doctrine/numeric-filter.feature
rename to features/doctrine/numeric_filter.feature
diff --git a/features/doctrine/order-filter.feature b/features/doctrine/order_filter.feature
similarity index 100%
rename from features/doctrine/order-filter.feature
rename to features/doctrine/order_filter.feature
diff --git a/features/doctrine/range-filter.feature b/features/doctrine/range_filter.feature
similarity index 100%
rename from features/doctrine/range-filter.feature
rename to features/doctrine/range_filter.feature
diff --git a/features/doctrine/search-filter.feature b/features/doctrine/search_filter.feature
similarity index 100%
rename from features/doctrine/search-filter.feature
rename to features/doctrine/search_filter.feature
diff --git a/features/fos-user.feature b/features/fos_user.feature
similarity index 96%
rename from features/fos-user.feature
rename to features/fos_user.feature
index 7ef920fd8bd..9d8e186643c 100644
--- a/features/fos-user.feature
+++ b/features/fos_user.feature
@@ -10,6 +10,7 @@ Feature: Create-Retrieve-Update-Delete
"""
{
"fullname": "Dummy User",
+ "username": "dummy.user",
"email": "dummy.user@example.com",
"plainPassword": "azerty"
}
diff --git a/features/json-ld/context.feature b/features/jsonld/context.feature
similarity index 100%
rename from features/json-ld/context.feature
rename to features/jsonld/context.feature
diff --git a/features/overriding-attribute.feature b/features/overridden_operation.feature
similarity index 51%
rename from features/overriding-attribute.feature
rename to features/overridden_operation.feature
index 8ebb11d4b98..a19ededcdf1 100644
--- a/features/overriding-attribute.feature
+++ b/features/overridden_operation.feature
@@ -1,14 +1,14 @@
-Feature: Create-Retrieve-Update-Delete with custom attribute
+Feature: Create-Retrieve-Update-Delete with a Overridden Operation context
In order to use an hypermedia API
As a client software developer
I need to be able to retrieve, create, update and delete JSON-LD encoded resources.
@createSchema
Scenario: Create a resource
- When I send a "POST" request to "/custom_attribute_dummies" with body:
+ When I send a "POST" request to "/overridden_operation_dummies" with body:
"""
{
- "name": "My Custom Attribute Dummy",
+ "name": "My Overridden Operation Dummy",
"description" : "Gerard",
"alias": "notWritable"
}
@@ -19,52 +19,63 @@ Feature: Create-Retrieve-Update-Delete with custom attribute
And the JSON should be equal to:
"""
{
- "@context": "/contexts/CustomAttributeDummy",
- "@id": "/custom_attribute_dummies/1",
- "@type": "CustomAttributeDummy",
- "name": "My Custom Attribute Dummy",
+ "@context": "/contexts/OverriddenOperationDummy",
+ "@id": "/overridden_operation_dummies/1",
+ "@type": "OverriddenOperationDummy",
+ "name": "My Overridden Operation Dummy",
"alias": null,
"description": "Gerard"
}
"""
Scenario: Get a resource
- When I send a "GET" request to "/custom_attribute_dummies/1"
+ When I send a "GET" request to "/overridden_operation_dummies/1"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json"
And the JSON should be equal to:
"""
{
- "@context": "/contexts/CustomAttributeDummy",
- "@id": "/custom_attribute_dummies/1",
- "@type": "CustomAttributeDummy",
- "name": "My Custom Attribute Dummy",
+ "@context": "/contexts/OverriddenOperationDummy",
+ "@id": "/overridden_operation_dummies/1",
+ "@type": "OverriddenOperationDummy",
+ "name": "My Overridden Operation Dummy",
"alias": null,
"description": "Gerard"
}
"""
+ Scenario: Get a resource in XML
+ When I add "Accept" header equal to "application/xml"
+ And I send a "GET" request to "/overridden_operation_dummies/1"
+ Then the response status code should be 200
+ And the header "Content-Type" should be equal to "application/xml"
+ And the response should be equal to
+ """
+
+My Overridden Operation DummyGerard
+ """
+
Scenario: Get a not found exception
- When I send a "GET" request to "/custom_attribute_dummies/42"
+ When I send a "GET" request to "/overridden_operation_dummies/42"
Then the response status code should be 404
Scenario: Get a collection
- When I send a "GET" request to "/custom_attribute_dummies"
+ When I send a "GET" request to "/overridden_operation_dummies"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json"
And the JSON should be equal to:
"""
{
- "@context": "/contexts/CustomAttributeDummy",
- "@id": "\/custom_attribute_dummies",
+ "@context": "/contexts/OverriddenOperationDummy",
+ "@id": "\/overridden_operation_dummies",
"@type": "hydra:Collection",
"hydra:member": [
{
- "@id": "\/custom_attribute_dummies\/1",
- "@type": "CustomAttributeDummy",
- "name": "My Custom Attribute Dummy",
+ "@id": "\/overridden_operation_dummies\/1",
+ "@type": "OverriddenOperationDummy",
+ "name": "My Overridden Operation Dummy",
"alias": null,
"description": "Gerard"
}
@@ -74,10 +85,10 @@ Feature: Create-Retrieve-Update-Delete with custom attribute
"""
Scenario: Update a resource
- When I send a "PUT" request to "/custom_attribute_dummies/1" with body:
+ When I send a "PUT" request to "/overridden_operation_dummies/1" with body:
"""
{
- "@id": "/custom_attribute_dummies/1",
+ "@id": "/overridden_operation_dummies/1",
"name": "A nice dummy",
"alias": "Dummy"
}
@@ -88,32 +99,33 @@ Feature: Create-Retrieve-Update-Delete with custom attribute
And the JSON should be equal to:
"""
{
- "@context": "/contexts/CustomAttributeDummy",
- "@id": "/custom_attribute_dummies/1",
- "@type": "CustomAttributeDummy",
+ "@context": "/contexts/OverriddenOperationDummy",
+ "@id": "/overridden_operation_dummies/1",
+ "@type": "OverriddenOperationDummy",
"alias": "Dummy",
"description": "Gerard"
}
"""
Scenario: Get the final resource
- When I send a "GET" request to "/custom_attribute_dummies/1"
+ When I send a "GET" request to "/overridden_operation_dummies/1"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json"
And the JSON should be equal to:
"""
{
- "@context": "/contexts/CustomAttributeDummy",
- "@id": "/custom_attribute_dummies/1",
- "@type": "CustomAttributeDummy",
- "name": "My Custom Attribute Dummy",
+ "@context": "/contexts/OverriddenOperationDummy",
+ "@id": "/overridden_operation_dummies/1",
+ "@type": "OverriddenOperationDummy",
+ "name": "My Overridden Operation Dummy",
"alias": "Dummy",
"description": "Gerard"
}
"""
+
@dropSchema
Scenario: Delete a resource
- When I send a "DELETE" request to "/custom_attribute_dummies/1"
+ When I send a "DELETE" request to "/overridden_operation_dummies/1"
Then the response status code should be 204
And the response should be empty
diff --git a/src/Action/GetCollectionAction.php b/src/Action/GetCollectionAction.php
index 57f93b8c0b7..3eedae4a9bb 100644
--- a/src/Action/GetCollectionAction.php
+++ b/src/Action/GetCollectionAction.php
@@ -42,8 +42,8 @@ public function __construct(CollectionDataProviderInterface $collectionDataProvi
*/
public function __invoke(Request $request)
{
- list($resourceClass, $operationName) = RequestAttributesExtractor::extractAttributes($request);
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
- return $this->collectionDataProvider->getCollection($resourceClass, $operationName);
+ return $this->collectionDataProvider->getCollection($attributes['resource_class'], $attributes['collection_operation_name']);
}
}
diff --git a/src/Action/GetItemAction.php b/src/Action/GetItemAction.php
index f0a74c1f160..f0083666bec 100644
--- a/src/Action/GetItemAction.php
+++ b/src/Action/GetItemAction.php
@@ -44,9 +44,9 @@ public function __construct(ItemDataProviderInterface $itemDataProvider)
*/
public function __invoke(Request $request, $id)
{
- list($resourceClass, , $operationName) = RequestAttributesExtractor::extractAttributes($request);
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
- $data = $this->itemDataProvider->getItem($resourceClass, $id, $operationName, true);
+ $data = $this->itemDataProvider->getItem($attributes['resource_class'], $id, $attributes['item_operation_name'], true);
if (!$data) {
throw new NotFoundHttpException('Not Found');
}
diff --git a/src/Api/RequestAttributesExtractor.php b/src/Api/RequestAttributesExtractor.php
index 6027a2289a5..a5fbd14cc84 100644
--- a/src/Api/RequestAttributesExtractor.php
+++ b/src/Api/RequestAttributesExtractor.php
@@ -18,12 +18,16 @@
* Extracts data used by the library form a Request instance.
*
* @author Kévin Dunglas
+ *
+ * @internal
*/
final class RequestAttributesExtractor
{
+ const API_ATTRIBUTES = ['resource_class', 'format', 'mime_type'];
+
/**
- * Extracts resource class, operation name and format request attributes. Throws an exception if the request does not contain required
- * attributes.
+ * Extracts resource class, operation name and format request attributes. Throws an exception if the request does not
+ * contain required attributes.
*
* @param Request $request
*
@@ -33,24 +37,30 @@ final class RequestAttributesExtractor
*/
public static function extractAttributes(Request $request)
{
- $resourceClass = $request->attributes->get('_resource_class');
+ $result = [];
- if (!$resourceClass) {
- throw new RuntimeException('The request attribute "_resource_class" must be defined.');
- }
+ foreach (self::API_ATTRIBUTES as $key) {
+ $attributeKey = '_api_'.$key;
+ $attributeValue = $request->attributes->get($attributeKey);
- $collectionOperation = $request->attributes->get('_collection_operation_name');
- $itemOperation = $request->attributes->get('_item_operation_name');
+ if (null === $attributeValue) {
+ throw new RuntimeException(sprintf('The request attribute "%s" must be defined.', $attributeKey));
+ }
- if (!$itemOperation && !$collectionOperation) {
- throw new RuntimeException('One of the request attribute "_item_operation_name" or "_collection_operation_name" must be defined.');
+ $result[$key] = $attributeValue;
}
- $format = $request->attributes->get('_api_format');
- if (!$format) {
- throw new RuntimeException('The request attribute "_api_format" must be defined.');
+ $collectionOperationName = $request->attributes->get('_api_collection_operation_name');
+ $itemOperationName = $request->attributes->get('_api_item_operation_name');
+
+ if ($collectionOperationName) {
+ $result['collection_operation_name'] = $collectionOperationName;
+ } elseif ($itemOperationName) {
+ $result['item_operation_name'] = $itemOperationName;
+ } else {
+ throw new RuntimeException('One of the request attribute "_api_collection_operation_name" or "_api_item_operation_name" must be defined.');
}
- return [$resourceClass, $collectionOperation, $itemOperation, $format];
+ return $result;
}
}
diff --git a/src/Bridge/Doctrine/EventListener/ManagerViewListener.php b/src/Bridge/Doctrine/EventListener/ManagerViewListener.php
index bb84e0b416d..38cc0bae96c 100644
--- a/src/Bridge/Doctrine/EventListener/ManagerViewListener.php
+++ b/src/Bridge/Doctrine/EventListener/ManagerViewListener.php
@@ -40,17 +40,16 @@ public function __construct(ManagerRegistry $managerRegistry)
public function onKernelView(GetResponseForControllerResultEvent $event)
{
$request = $event->getRequest();
- if (!in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_DELETE])) {
+ if (!in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_DELETE], true)) {
return;
}
- $resourceClass = $request->attributes->get('_resource_class');
- if (!$resourceClass) {
+ $resourceClass = $request->attributes->get('_api_resource_class');
+ if (null === $resourceClass) {
return;
}
$controllerResult = $event->getControllerResult();
-
if (null === $objectManager = $this->getManager($resourceClass, $controllerResult)) {
return $controllerResult;
}
diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
index 0467ba1480a..a624db8af43 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
@@ -52,10 +52,10 @@ public function load(array $configs, ContainerBuilder $container)
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
- $supportedFormats = [];
- foreach ($config['supported_formats'] as $format => $value) {
+ $formats = [];
+ foreach ($config['formats'] as $format => $value) {
foreach ($value['mime_types'] as $mimeType) {
- $supportedFormats[$mimeType] = $format;
+ $formats[$mimeType] = $format;
}
}
@@ -67,7 +67,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('api_platform.title', $config['title']);
$container->setParameter('api_platform.description', $config['description']);
- $container->setParameter('api_platform.supported_formats', $supportedFormats);
+ $container->setParameter('api_platform.formats', $formats);
$container->setParameter('api_platform.collection.order', $config['collection']['order']);
$container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
$container->setParameter('api_platform.collection.pagination.enabled', $config['collection']['pagination']['enabled']);
diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
index ce73047c2fb..d20cf12d58c 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
@@ -33,7 +33,7 @@ public function getConfigTreeBuilder()
->children()
->scalarNode('title')->defaultValue('')->info('The title of the API.')->end()
->scalarNode('description')->defaultValue('')->info('The description of the API.')->end()
- ->arrayNode('supported_formats')
+ ->arrayNode('formats')
->defaultValue(['jsonld' => ['mime_types' => ['application/ld+json']]])
->info('The list of enabled formats. The first one will be the default.')
->normalizeKeys(false)
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
index 86cd5eddd42..6d90d0d8070 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
@@ -43,6 +43,12 @@
+
+
+
+
+
+
@@ -53,22 +59,34 @@
- %api_platform.supported_formats%
+ %api_platform.formats%
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
+
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml b/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
index 0a322a171c0..4656cfa07eb 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
@@ -76,7 +76,7 @@
-
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/hydra.xml b/src/Bridge/Symfony/Bundle/Resources/config/hydra.xml
index 2e951c3e0b8..77cd32bbeae 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/hydra.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/hydra.xml
@@ -44,7 +44,6 @@
-
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml b/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
index 75783eff304..3a442234b58 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
@@ -39,14 +39,6 @@
-
-
-
-
-
-
-
-
diff --git a/src/Bridge/Symfony/Routing/ApiLoader.php b/src/Bridge/Symfony/Routing/ApiLoader.php
index e9cd653db69..180abf17369 100644
--- a/src/Bridge/Symfony/Routing/ApiLoader.php
+++ b/src/Bridge/Symfony/Routing/ApiLoader.php
@@ -35,7 +35,6 @@ final class ApiLoader extends Loader
const ROUTE_NAME_PREFIX = 'api_';
const DEFAULT_ACTION_PATTERN = 'api_platform.action.';
- private $kernel;
private $fileLoader;
private $resourceNameCollectionFactory;
private $resourceMetadataFactory;
@@ -44,11 +43,11 @@ final class ApiLoader extends Loader
public function __construct(KernelInterface $kernel, ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourcePathGeneratorInterface $resourcePathGenerator, ContainerInterface $container)
{
- $this->container = $container;
$this->fileLoader = new XmlFileLoader(new FileLocator($kernel->locateResource('@ApiPlatformBundle/Resources/config/routing')));
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
$this->resourceMetadataFactory = $resourceMetadataFactory;
$this->resourcePathGenerator = $resourcePathGenerator;
+ $this->container = $container;
}
/**
@@ -144,8 +143,8 @@ private function addRoute(RouteCollection $routeCollection, string $resourceClas
$path,
[
'_controller' => $controller,
- '_resource_class' => $resourceClass,
- sprintf('_%s_operation_name', $collection ? 'collection' : 'item') => $operationName,
+ '_api_resource_class' => $resourceClass,
+ sprintf('_api_%s_operation_name', $collection ? 'collection' : 'item') => $operationName,
],
[],
[],
diff --git a/src/Bridge/Symfony/Routing/IriConverter.php b/src/Bridge/Symfony/Routing/IriConverter.php
index df84e441b7e..f3495687f8f 100644
--- a/src/Bridge/Symfony/Routing/IriConverter.php
+++ b/src/Bridge/Symfony/Routing/IriConverter.php
@@ -58,11 +58,11 @@ public function getItemFromIri(string $iri, bool $fetchData = false)
throw new InvalidArgumentException(sprintf('No route matches "%s".', $iri), $exception->getCode(), $exception);
}
- if (!isset($parameters['_resource_class']) || !isset($parameters['id'])) {
+ if (!isset($parameters['_api_resource_class']) || !isset($parameters['id'])) {
throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
}
- if ($item = $this->itemDataProvider->getItem($parameters['_resource_class'], $parameters['id'], null, $fetchData)) {
+ if ($item = $this->itemDataProvider->getItem($parameters['_api_resource_class'], $parameters['id'], null, $fetchData)) {
return $item;
}
@@ -175,8 +175,8 @@ private function getRouteName(string $resourceClass, bool $collection) : string
$operationType = $collection ? 'collection' : 'item';
foreach ($this->router->getRouteCollection()->all() as $routeName => $route) {
- $currentResourceClass = $route->getDefault('_resource_class');
- $operation = $route->getDefault(sprintf('_%s_operation_name', $operationType));
+ $currentResourceClass = $route->getDefault('_api_resource_class');
+ $operation = $route->getDefault(sprintf('_api_%s_operation_name', $operationType));
$methods = $route->getMethods();
if ($resourceClass === $currentResourceClass && null !== $operation && (empty($methods) || in_array('GET', $methods))) {
diff --git a/src/Bridge/Symfony/Routing/OperationMethodResolver.php b/src/Bridge/Symfony/Routing/OperationMethodResolver.php
index 7a7c6c46bc9..66a17a658c6 100644
--- a/src/Bridge/Symfony/Routing/OperationMethodResolver.php
+++ b/src/Bridge/Symfony/Routing/OperationMethodResolver.php
@@ -127,10 +127,10 @@ private function getOperationMethod(string $resourceClass, string $operationName
*/
private function getOperationRoute(string $resourceClass, string $operationName, bool $collection) : Route
{
- $operationNameKey = sprintf('_%s_operation_name', $collection ? 'collection' : 'item');
+ $operationNameKey = sprintf('_api_%s_operation_name', $collection ? 'collection' : 'item');
foreach ($this->router->getRouteCollection()->all() as $routeName => $route) {
- $currentResourceClass = $route->getDefault('_resource_class');
+ $currentResourceClass = $route->getDefault('_api_resource_class');
$currentOperationName = $route->getDefault($operationNameKey);
if ($resourceClass === $currentResourceClass && $operationName === $currentOperationName) {
diff --git a/src/Bridge/Symfony/Validator/EventListener/ViewListener.php b/src/Bridge/Symfony/Validator/EventListener/ValidatorViewListener.php
similarity index 70%
rename from src/Bridge/Symfony/Validator/EventListener/ViewListener.php
rename to src/Bridge/Symfony/Validator/EventListener/ValidatorViewListener.php
index 41c15bbfa2d..aeb05defb77 100644
--- a/src/Bridge/Symfony/Validator/EventListener/ViewListener.php
+++ b/src/Bridge/Symfony/Validator/EventListener/ValidatorViewListener.php
@@ -11,7 +11,9 @@
namespace ApiPlatform\Core\Bridge\Symfony\Validator\EventListener;
+use ApiPlatform\Core\Api\RequestAttributesExtractor;
use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
+use ApiPlatform\Core\Exception\RuntimeException;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
@@ -22,15 +24,15 @@
*
* @author Kévin Dunglas
*/
-final class ViewListener
+final class ValidatorViewListener
{
- private $resourceMetadataFactory;
private $validator;
+ private $resourceMetadataFactory;
- public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, ValidatorInterface $validator)
+ public function __construct(ValidatorInterface $validator, ResourceMetadataFactoryInterface $resourceMetadataFactory)
{
- $this->resourceMetadataFactory = $resourceMetadataFactory;
$this->validator = $validator;
+ $this->resourceMetadataFactory = $resourceMetadataFactory;
}
/**
@@ -44,26 +46,24 @@ public function onKernelView(GetResponseForControllerResultEvent $event)
{
$request = $event->getRequest();
- $resourceClass = $request->attributes->get('_resource_class');
- $itemOperationName = $request->attributes->get('_item_operation_name');
- $collectionOperationName = $request->attributes->get('_collection_operation_name');
+ try {
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
+ } catch (RuntimeException $e) {
+ return;
+ }
- $method = $request->getMethod();
- if (
- !$resourceClass || (!$itemOperationName && !$collectionOperationName) ||
- (Request::METHOD_POST !== $method && Request::METHOD_PUT !== $method && Request::METHOD_PATCH !== $method)
- ) {
+ if (!in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH], true)) {
return;
}
$data = $event->getControllerResult();
- $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
+ $resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']);
- if ($collectionOperationName) {
- $validationGroups = $resourceMetadata->getCollectionOperationAttribute($collectionOperationName, 'validation_groups');
+ if (isset($attributes['collection_operation_name'])) {
+ $validationGroups = $resourceMetadata->getCollectionOperationAttribute($attributes['collection_operation_name'], 'validation_groups');
} else {
- $validationGroups = $resourceMetadata->getItemOperationAttribute($itemOperationName, 'validation_groups');
+ $validationGroups = $resourceMetadata->getItemOperationAttribute($attributes['item_operation_name'], 'validation_groups');
}
if (!$validationGroups) {
diff --git a/src/Bridge/Symfony/Validator/Hydra/EventListener/ValidationExceptionListener.php b/src/Bridge/Symfony/Validator/Hydra/EventListener/ValidationExceptionListener.php
index fcdda16cd8f..9a35ebabb21 100644
--- a/src/Bridge/Symfony/Validator/Hydra/EventListener/ValidationExceptionListener.php
+++ b/src/Bridge/Symfony/Validator/Hydra/EventListener/ValidationExceptionListener.php
@@ -12,7 +12,7 @@
namespace ApiPlatform\Core\Bridge\Symfony\Validator\Hydra\EventListener;
use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
-use ApiPlatform\Core\JsonLd\Response;
+use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -40,9 +40,10 @@ public function onKernelException(GetResponseForExceptionEvent $event)
$exception = $event->getException();
if ($exception instanceof ValidationException) {
- $event->setResponse(new Response(
+ $event->setResponse(new JsonResponse(
$this->normalizer->normalize($exception->getConstraintViolationList(), 'hydra-error'),
- Response::HTTP_BAD_REQUEST
+ JsonResponse::HTTP_BAD_REQUEST,
+ ['Content-Type' => 'application/ld+json']
));
}
}
diff --git a/src/EventListener/DeserializerViewListener.php b/src/EventListener/DeserializerViewListener.php
index 43dda05b79d..d406cdd7c26 100644
--- a/src/EventListener/DeserializerViewListener.php
+++ b/src/EventListener/DeserializerViewListener.php
@@ -13,6 +13,7 @@
use ApiPlatform\Core\Api\RequestAttributesExtractor;
use ApiPlatform\Core\Exception\RuntimeException;
+use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
@@ -26,38 +27,41 @@
final class DeserializerViewListener
{
private $serializer;
+ private $serializerContextBuilder;
- public function __construct(SerializerInterface $serializer)
+ public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder)
{
$this->serializer = $serializer;
+ $this->serializerContextBuilder = $serializerContextBuilder;
}
+ /**
+ * Deserializes the data sent in the requested format.
+ *
+ * @param GetResponseForControllerResultEvent $event
+ */
public function onKernelView(GetResponseForControllerResultEvent $event)
{
- $data = $event->getControllerResult();
+ $controllerResult = $event->getControllerResult();
$request = $event->getRequest();
- if ($data instanceof Response || !in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT], true)) {
+ if ($controllerResult instanceof Response || !in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT], true)) {
return;
}
try {
- list($resourceClass, $collectionOperation, $itemOperation, $format) = RequestAttributesExtractor::extractAttributes($request);
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
} catch (RuntimeException $e) {
return;
}
- $context = ['resource_class' => $resourceClass];
- if ($collectionOperation) {
- $context['collection_operation_name'] = $collectionOperation;
- } else {
- $context['item_operation_name'] = $itemOperation;
+ $context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes);
+ if (null !== $controllerResult) {
+ $context['object_to_populate'] = $controllerResult;
}
- if (null !== $data) {
- $context['object_to_populate'] = $data;
- }
-
- $event->setControllerResult($this->serializer->deserialize($request->getContent(), $resourceClass, $format, $context));
+ $event->setControllerResult(
+ $this->serializer->deserialize($request->getContent(), $attributes['resource_class'], $attributes['format'], $context)
+ );
}
}
diff --git a/src/EventListener/FormatRequestListener.php b/src/EventListener/FormatRequestListener.php
index c026a285512..ff94b6889d2 100644
--- a/src/EventListener/FormatRequestListener.php
+++ b/src/EventListener/FormatRequestListener.php
@@ -22,12 +22,12 @@
final class FormatRequestListener
{
private $negotiator;
- private $supportedFormats;
+ private $formats;
- public function __construct(Negotiator $negotiator, array $supportedFormats)
+ public function __construct(Negotiator $negotiator, array $formats)
{
$this->negotiator = $negotiator;
- $this->supportedFormats = $supportedFormats;
+ $this->formats = $formats;
}
/**
@@ -36,23 +36,34 @@ public function __construct(Negotiator $negotiator, array $supportedFormats)
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
- if (!$request->attributes->get('_resource_class')) {
+ if (null === $request->attributes->get('_api_resource_class')) {
return;
}
// Use the Symfony request format if available and applicable
$requestFormat = $request->getRequestFormat(null);
$mimeType = $requestFormat ? $request->getMimeType($requestFormat) : null;
- if (null === $mimeType || !in_array($mimeType, $this->supportedFormats)) {
+ if (null === $mimeType || !in_array($mimeType, $this->formats)) {
if (null === $accept = $request->headers->get('Accept')) {
$mimeType = null;
} else {
// Try to guess the best format to use
- $acceptHeader = $this->negotiator->getBest($accept, array_keys($this->supportedFormats));
+ $acceptHeader = $this->negotiator->getBest($accept, array_keys($this->formats));
$mimeType = $acceptHeader ? $acceptHeader->getType() : null;
}
}
- $request->attributes->set('_api_format', $mimeType ? $this->supportedFormats[$mimeType] : reset($this->supportedFormats));
+ if ($mimeType) {
+ $request->attributes->set('_api_mime_type', $mimeType);
+ $request->attributes->set('_api_format', $this->formats[$mimeType]);
+
+ return;
+ }
+
+ reset($this->formats);
+ $format = each($this->formats);
+
+ $request->attributes->set('_api_mime_type', $format['key']);
+ $request->attributes->set('_api_format', $format['value']);
}
}
diff --git a/src/EventListener/ResponderViewListener.php b/src/EventListener/ResponderViewListener.php
new file mode 100644
index 00000000000..be8828fcf38
--- /dev/null
+++ b/src/EventListener/ResponderViewListener.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\EventListener;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+
+/**
+ * Builds the response object.
+ *
+ * @author Kévin Dunglas
+ */
+final class ResponderViewListener
+{
+ const METHOD_TO_CODE = [
+ Request::METHOD_POST => Response::HTTP_CREATED,
+ Request::METHOD_DELETE => Response::HTTP_NO_CONTENT,
+ ];
+
+ /**
+ * Creates a Response to send to the client according to the requested format.
+ */
+ public function onKernelView(GetResponseForControllerResultEvent $event)
+ {
+ $controllerResult = $event->getControllerResult();
+ $request = $event->getRequest();
+ $mimeType = $request->attributes->get('_api_mime_type');
+
+ if ($controllerResult instanceof Response || !$mimeType) {
+ return;
+ }
+
+ $event->setResponse(new Response(
+ $controllerResult,
+ self::METHOD_TO_CODE[$request->getMethod()] ?? Response::HTTP_OK,
+ ['Content-Type' => $request->attributes->get('_api_mime_type')]
+ ));
+ }
+}
diff --git a/src/EventListener/SerializerViewListener.php b/src/EventListener/SerializerViewListener.php
new file mode 100644
index 00000000000..d1eca75f8cc
--- /dev/null
+++ b/src/EventListener/SerializerViewListener.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\EventListener;
+
+use ApiPlatform\Core\Api\RequestAttributesExtractor;
+use ApiPlatform\Core\Exception\RuntimeException;
+use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * Serializes data.
+ *
+ * @author Kévin Dunglas
+ */
+final class SerializerViewListener
+{
+ private $serializer;
+ private $serializerContextBuilder;
+
+ public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder)
+ {
+ $this->serializer = $serializer;
+ $this->serializerContextBuilder = $serializerContextBuilder;
+ }
+
+ /**
+ * Serializes the data to the requested format.
+ *
+ * @param GetResponseForControllerResultEvent $event
+ */
+ public function onKernelView(GetResponseForControllerResultEvent $event)
+ {
+ $controllerResult = $event->getControllerResult();
+ $request = $event->getRequest();
+
+ if ($controllerResult instanceof Response) {
+ return;
+ }
+
+ try {
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
+ } catch (RuntimeException $e) {
+ return;
+ }
+
+ $context = $this->serializerContextBuilder->createFromRequest($request, true, $attributes);
+ $event->setControllerResult($this->serializer->serialize($controllerResult, $attributes['format'], $context));
+ }
+}
diff --git a/src/Hydra/Action/DocumentationAction.php b/src/Hydra/Action/DocumentationAction.php
index 3e5c90db8e1..a16cc15f516 100644
--- a/src/Hydra/Action/DocumentationAction.php
+++ b/src/Hydra/Action/DocumentationAction.php
@@ -12,7 +12,7 @@
namespace ApiPlatform\Core\Hydra\Action;
use ApiPlatform\Core\Hydra\ApiDocumentationBuilderInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Generates the Hydra API documentation.
@@ -30,15 +30,9 @@ public function __construct(ApiDocumentationBuilderInterface $apiDocumentationBu
/**
* Gets API doc.
- *
- * @param Request $request
- *
- * @return array
*/
- public function __invoke(Request $request)
+ public function __invoke() : JsonResponse
{
- $request->attributes->set('_api_format', 'jsonld');
-
- return $this->apiDocumentationBuilder->getApiDocumentation();
+ return new JsonResponse($this->apiDocumentationBuilder->getApiDocumentation(), JsonResponse::HTTP_OK, ['Content-Type' => 'application/ld+json']);
}
}
diff --git a/src/Hydra/Action/ExceptionAction.php b/src/Hydra/Action/ExceptionAction.php
index e3f0707973a..f19d642726a 100644
--- a/src/Hydra/Action/ExceptionAction.php
+++ b/src/Hydra/Action/ExceptionAction.php
@@ -12,8 +12,8 @@
namespace ApiPlatform\Core\Hydra\Action;
use ApiPlatform\Core\Exception\InvalidArgumentException;
-use ApiPlatform\Core\JsonLd\Response;
use Symfony\Component\Debug\Exception\FlattenException;
+use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -32,27 +32,21 @@ public function __construct(NormalizerInterface $normalizer)
}
/**
- * Converts a {@see \Symfony\Component\Debug\Exception\FlattenException}
- * to a {@see \ApiPlatform\Core\JsonLd\Response}.
- *
- * @param FlattenException $exception
- *
- * @return Response
+ * Converts a an exception to a JSON response.
*/
- public function __invoke(FlattenException $exception)
+ public function __invoke(FlattenException $exception) : JsonResponse
{
$exceptionClass = $exception->getClass();
if (
is_a($exceptionClass, ExceptionInterface::class, true) ||
is_a($exceptionClass, InvalidArgumentException::class, true)
) {
- $exception->setStatusCode(Response::HTTP_BAD_REQUEST);
+ $exception->setStatusCode(JsonResponse::HTTP_BAD_REQUEST);
}
- return new Response(
- $this->normalizer->normalize($exception, 'hydra-error'),
- $exception->getStatusCode(),
- $exception->getHeaders()
- );
+ $headers = $exception->getHeaders();
+ $headers['Content-Type'] = 'application/ld+json';
+
+ return new JsonResponse($this->normalizer->normalize($exception, 'hydra-error'), $exception->getStatusCode(), $headers);
}
}
diff --git a/src/Hydra/EventListener/RequestExceptionListener.php b/src/Hydra/EventListener/RequestExceptionListener.php
index 8cd42a13869..6b8de13d5ca 100644
--- a/src/Hydra/EventListener/RequestExceptionListener.php
+++ b/src/Hydra/EventListener/RequestExceptionListener.php
@@ -25,7 +25,7 @@ final class RequestExceptionListener extends ExceptionListener
public function onKernelException(GetResponseForExceptionEvent $event)
{
// Normalize exceptions with hydra errors only for resources
- if (!$event->getRequest()->attributes->has('_resource_class')) {
+ if (!$event->getRequest()->attributes->has('_api_resource_class')) {
return;
}
diff --git a/src/Hydra/Serializer/CollectionFiltersNormalizer.php b/src/Hydra/Serializer/CollectionFiltersNormalizer.php
index e57ba25f2cf..d2cf0696542 100644
--- a/src/Hydra/Serializer/CollectionFiltersNormalizer.php
+++ b/src/Hydra/Serializer/CollectionFiltersNormalizer.php
@@ -64,7 +64,7 @@ public function normalize($object, $format = null, array $context = [])
return $data;
}
- $resourceClass = $this->getResourceClass($this->resourceClassResolver, $object, $context);
+ $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
$operationName = $context['collection_operation_name'] ?? null;
diff --git a/src/Hydra/Serializer/CollectionNormalizer.php b/src/Hydra/Serializer/CollectionNormalizer.php
index 5104997330d..17356e36c93 100644
--- a/src/Hydra/Serializer/CollectionNormalizer.php
+++ b/src/Hydra/Serializer/CollectionNormalizer.php
@@ -17,7 +17,6 @@
use ApiPlatform\Core\Exception\RuntimeException;
use ApiPlatform\Core\JsonLd\ContextBuilderInterface;
use ApiPlatform\Core\JsonLd\Serializer\ContextTrait;
-use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
@@ -35,14 +34,12 @@ final class CollectionNormalizer implements NormalizerInterface, SerializerAware
const FORMAT = 'jsonld';
- private $resourceMetadataFactory;
private $contextBuilder;
private $resourceClassResolver;
private $iriConverter;
- public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, ContextBuilderInterface $contextBuilder, ResourceClassResolverInterface $resourceClassResolver, IriConverterInterface $iriConverter)
+ public function __construct(ContextBuilderInterface $contextBuilder, ResourceClassResolverInterface $resourceClassResolver, IriConverterInterface $iriConverter)
{
- $this->resourceMetadataFactory = $resourceMetadataFactory;
$this->contextBuilder = $contextBuilder;
$this->resourceClassResolver = $resourceClassResolver;
$this->iriConverter = $iriConverter;
@@ -78,10 +75,9 @@ public function normalize($object, $format = null, array $context = [])
return $data;
}
- $resourceClass = $this->getResourceClass($this->resourceClassResolver, $object, $context);
- $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
+ $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
$data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context);
- $context = $this->createContext($resourceClass, $resourceMetadata, $context, true);
+ $context = $this->createContext($resourceClass, $context);
$data['@id'] = $this->iriConverter->getIriFromResourceClass($resourceClass);
$data['@type'] = 'hydra:Collection';
diff --git a/src/JsonLd/Action/ContextAction.php b/src/JsonLd/Action/ContextAction.php
index c60c28b473d..5e4998972a9 100644
--- a/src/JsonLd/Action/ContextAction.php
+++ b/src/JsonLd/Action/ContextAction.php
@@ -14,7 +14,7 @@
use ApiPlatform\Core\JsonLd\ContextBuilderInterface;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
@@ -43,30 +43,23 @@ public function __construct(ContextBuilderInterface $contextBuilder, ResourceNam
/**
* Generates a context according to the type requested.
*
- * @param Request $request
- * @param string $shortName
- *
* @throws NotFoundHttpException
- *
- * @return array
*/
- public function __invoke(Request $request, string $shortName) : array
+ public function __invoke(string $shortName) : JsonResponse
{
- $request->attributes->set('_api_format', 'jsonld');
-
if ('Entrypoint' === $shortName) {
return ['@context' => $this->contextBuilder->getEntrypointContext()];
}
if (isset(self::RESERVED_SHORT_NAMES[$shortName])) {
- return ['@context' => $this->contextBuilder->getBaseContext()];
+ return new JsonResponse(['@context' => $this->contextBuilder->getBaseContext()], JsonResponse::HTTP_OK, ['Content-Type' => 'application/ld+json']);
}
foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
if ($shortName === $resourceMetadata->getShortName()) {
- return ['@context' => $this->contextBuilder->getResourceContext($resourceClass)];
+ return new JsonResponse(['@context' => $this->contextBuilder->getResourceContext($resourceClass)], JsonResponse::HTTP_OK, ['Content-Type' => 'application/ld+json']);
}
}
diff --git a/src/JsonLd/Action/EntrypointAction.php b/src/JsonLd/Action/EntrypointAction.php
index 2dda49c186e..8094c10f67a 100644
--- a/src/JsonLd/Action/EntrypointAction.php
+++ b/src/JsonLd/Action/EntrypointAction.php
@@ -12,7 +12,7 @@
namespace ApiPlatform\Core\JsonLd\Action;
use ApiPlatform\Core\JsonLd\EntrypointBuilderInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Generates the JSON-LD API entrypoint.
@@ -28,17 +28,8 @@ public function __construct(EntrypointBuilderInterface $entrypointBuilder)
$this->entrypointBuilder = $entrypointBuilder;
}
- /**
- * Builds the entrypoint.
- *
- * @param Request $request
- *
- * @return array
- */
- public function __invoke(Request $request) : array
+ public function __invoke() : JsonResponse
{
- $request->attributes->set('_api_format', 'jsonld');
-
- return $this->entrypointBuilder->getEntrypoint();
+ return new JsonResponse($this->entrypointBuilder->getEntrypoint(), JsonResponse::HTTP_OK, ['Content-Type' => 'application/ld+json']);
}
}
diff --git a/src/JsonLd/EventListener/ResponderViewListener.php b/src/JsonLd/EventListener/ResponderViewListener.php
deleted file mode 100644
index b6627b81a0c..00000000000
--- a/src/JsonLd/EventListener/ResponderViewListener.php
+++ /dev/null
@@ -1,92 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace ApiPlatform\Core\JsonLd\EventListener;
-
-use ApiPlatform\Core\JsonLd\Response as JsonLdResponse;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
-use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
-
-/**
- * Normalizes data then builds the response object.
- *
- * @author Kévin Dunglas
- */
-final class ResponderViewListener
-{
- const FORMAT = 'jsonld';
-
- private $normalizer;
-
- public function __construct(NormalizerInterface $normalizer)
- {
- $this->normalizer = $normalizer;
- }
-
- /**
- * In an API context, converts any data to a JSON-LD response.
- *
- * @param GetResponseForControllerResultEvent $event
- *
- * @return JsonLdResponse|mixed
- */
- public function onKernelView(GetResponseForControllerResultEvent $event)
- {
- $controllerResult = $event->getControllerResult();
-
- if ($controllerResult instanceof Response) {
- return;
- }
-
- $request = $event->getRequest();
-
- $format = $request->attributes->get('_api_format');
- if (self::FORMAT !== $format) {
- return;
- }
-
- switch ($request->getMethod()) {
- case Request::METHOD_POST:
- $status = 201;
- break;
-
- case Request::METHOD_DELETE:
- $status = 204;
- break;
-
- default:
- $status = 200;
- break;
- }
-
- $resourceClass = $request->attributes->get('_resource_class');
- $collectionOperationName = $request->attributes->get('_collection_operation_name');
- $itemOperationName = $request->attributes->get('_item_operation_name');
-
- if (!$resourceClass || (!$collectionOperationName && !$itemOperationName)) {
- $event->setResponse(new JsonLdResponse($controllerResult, $status));
-
- return;
- }
-
- $context = ['request_uri' => $request->getRequestUri(), 'resource_class' => $resourceClass];
- if ($collectionOperationName) {
- $context['collection_operation_name'] = $collectionOperationName;
- } else {
- $context['item_operation_name'] = $itemOperationName;
- }
-
- $response = new JsonLdResponse($this->normalizer->normalize($controllerResult, self::FORMAT, $context), $status);
- $event->setResponse($response);
- }
-}
diff --git a/src/JsonLd/Response.php b/src/JsonLd/Response.php
deleted file mode 100644
index 62b77d37b90..00000000000
--- a/src/JsonLd/Response.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.
- */
-
-namespace ApiPlatform\Core\JsonLd;
-
-use Symfony\Component\HttpFoundation\JsonResponse;
-
-/**
- * JSON-LD Response.
- *
- * @author Kévin Dunglas
- */
-class Response extends JsonResponse
-{
- /**
- * {@inheritdoc}
- */
- protected function update()
- {
- // Only set the header when there is none or when it equals 'application/ld+json' (from a previous update with callback)
- // in order to not overwrite a custom definition.
- if (!$this->headers->has('Content-Type') || 'application/ld+json' === $this->headers->get('Content-Type')) {
- $this->headers->set('Content-Type', 'application/ld+json');
- }
-
- return $this->setContent($this->data);
- }
-}
diff --git a/src/JsonLd/Serializer/ContextTrait.php b/src/JsonLd/Serializer/ContextTrait.php
index 3d72a5134ef..0a96acf6bc4 100644
--- a/src/JsonLd/Serializer/ContextTrait.php
+++ b/src/JsonLd/Serializer/ContextTrait.php
@@ -11,101 +11,49 @@
namespace ApiPlatform\Core\JsonLd\Serializer;
-use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\JsonLd\ContextBuilderInterface;
-use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
/**
* Creates and manipulates the Serializer context.
*
* @author Kévin Dunglas
+ *
+ * @internal
*/
trait ContextTrait
{
/**
* Import the context defined in metadata and set some default values.
*
- * @param string $resourceClass
- * @param ResourceMetadata $resourceMetadata
- * @param array $context
+ * @param string $resourceClass
+ * @param array $context
*
* @return array
*/
- private function createContext(string $resourceClass, ResourceMetadata $resourceMetadata, array $context, bool $normalization) : array
+ private function createContext(string $resourceClass, array $context) : array
{
if (isset($context['jsonld_has_context'])) {
return $context;
}
- $key = $normalization ? 'normalization_context' : 'denormalization_context';
- $context = array_merge($context, $this->getContextValue($resourceMetadata, $context, $key, []));
- $context['resource_class'] = $resourceClass;
-
return array_merge($context, [
'jsonld_has_context' => true,
// Don't use hydra:Collection in sub levels
'jsonld_sub_level' => true,
+ 'resource_class' => $resourceClass,
]);
}
/**
- * Updates the resource class and remove the object_to_populate key.
+ * Updates the given JSON-LD document to add its @context key.
*
- * @param string $resourceClass
- * @param array $context
+ * @param ContextBuilderInterface $contextBuilder
+ * @param string $resourceClass
+ * @param array $context
+ * @param array $data
*
* @return array
*/
- private function createRelationContext(string $resourceClass, array $context) : array
- {
- $context['resource_class'] = $resourceClass;
- unset($context['item_operation_name']);
- unset($context['collection_operation_name']);
-
- return $context;
- }
-
- /**
- * Gets a context value.
- *
- * @param ResourceMetadata $resourceMetadata
- * @param array $context
- * @param string $key
- * @param mixed $defaultValue
- *
- * @return mixed
- */
- private function getContextValue(ResourceMetadata $resourceMetadata, array $context, string $key, $defaultValue = null)
- {
- if (isset($context[$key])) {
- return $context[$key];
- }
-
- if (isset($context['collection_operation_name'])) {
- return $resourceMetadata->getCollectionOperationAttribute($context['collection_operation_name'], $key, $defaultValue, true);
- }
-
- if (isset($context['item_operation_name'])) {
- return $resourceMetadata->getItemOperationAttribute($context['item_operation_name'], $key, $defaultValue, true);
- }
-
- return $resourceMetadata->getAttribute($key, $defaultValue);
- }
-
- /**
- * Gets the resource class to use depending of the current data and context.
- *
- * @param ResourceClassResolverInterface $resourceClassResolver
- * @param mixed $data
- * @param array $context
- *
- * @return string
- */
- private function getResourceClass(ResourceClassResolverInterface $resourceClassResolver, $data, array $context) : string
- {
- return $resourceClassResolver->getResourceClass($data, $context['resource_class'] ?? null, true);
- }
-
private function addJsonLdContext(ContextBuilderInterface $contextBuilder, string $resourceClass, array $context, array $data = []) : array
{
if (isset($context['jsonld_has_context'])) {
diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php
index fef644f5006..801f51f4c9e 100644
--- a/src/JsonLd/Serializer/ItemNormalizer.php
+++ b/src/JsonLd/Serializer/ItemNormalizer.php
@@ -84,13 +84,13 @@ public function supportsNormalization($data, $format = null)
*/
public function normalize($object, $format = null, array $context = [])
{
- $resourceClass = $this->getResourceClass($this->resourceClassResolver, $object, $context);
+ $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
$data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context);
$context['jsonld_normalize'] = true;
- $context = $this->createContext($resourceClass, $resourceMetadata, $context, true);
+ $context = $this->createContext($resourceClass, $context);
$rawData = parent::normalize($object, $format, $context);
if (!is_array($rawData)) {
@@ -116,11 +116,10 @@ public function supportsDenormalization($data, $type, $format = null)
*/
public function denormalize($data, $class, $format = null, array $context = [])
{
- $resourceClass = $this->getResourceClass($this->resourceClassResolver, $data, $context);
- $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
+ $resourceClass = $this->resourceClassResolver->getResourceClass($data, $context['resource_class']);
$context['jsonld_denormalize'] = true;
- $context = $this->createContext($resourceClass, $resourceMetadata, $context, false);
+ $context = $this->createContext($resourceClass, $context);
// Avoid issues with proxies if we populated the object
$overrideClass = isset($data['@id']) && !isset($context['object_to_populate']);
@@ -272,7 +271,7 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
private function normalizeRelation(PropertyMetadata $propertyMetadata, $relatedObject, string $resourceClass, array $context)
{
if ($propertyMetadata->isReadableLink()) {
- return $this->serializer->normalize($relatedObject, self::FORMAT, $this->createRelationContext($resourceClass, $context));
+ return $this->serializer->normalize($relatedObject, self::FORMAT, $this->createRelationSerializationContext($resourceClass, $context));
}
return $this->iriConverter->getIriFromItem($relatedObject);
@@ -303,7 +302,7 @@ private function denormalizeRelation(string $resourceClass, string $attributeNam
}
if (!$this->resourceClassResolver->isResourceClass($className) || $propertyMetadata->isWritableLink()) {
- return $this->serializer->denormalize($value, $className, self::FORMAT, $this->createRelationContext($className, $context));
+ return $this->serializer->denormalize($value, $className, self::FORMAT, $this->createRelationSerializationContext($className, $context));
}
if (!is_array($value)) {
@@ -364,4 +363,21 @@ private function getFactoryOptions(array $context) : array
return $options;
}
+
+ /**
+ * Creates the context to use when serializing a relation.
+ *
+ * @param string $resourceClass
+ * @param array $context
+ *
+ * @return array
+ */
+ private function createRelationSerializationContext(string $resourceClass, array $context) : array
+ {
+ $context['resource_class'] = $resourceClass;
+ unset($context['item_operation_name']);
+ unset($context['collection_operation_name']);
+
+ return $context;
+ }
}
diff --git a/src/JsonLd/Serializer/JsonLdEncoder.php b/src/JsonLd/Serializer/JsonLdEncoder.php
index 0e2e520004f..ba33f495bf9 100644
--- a/src/JsonLd/Serializer/JsonLdEncoder.php
+++ b/src/JsonLd/Serializer/JsonLdEncoder.php
@@ -11,6 +11,11 @@
namespace ApiPlatform\Core\JsonLd\Serializer;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\Serializer\Encoder\DecoderInterface;
+use Symfony\Component\Serializer\Encoder\EncoderInterface;
+use Symfony\Component\Serializer\Encoder\JsonDecode;
+use Symfony\Component\Serializer\Encoder\JsonEncode;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
/**
@@ -18,10 +23,20 @@
*
* @author Kévin Dunglas
*/
-final class JsonLdEncoder extends JsonEncoder
+final class JsonLdEncoder implements EncoderInterface, DecoderInterface
{
const FORMAT = 'jsonld';
+ private $jsonEncoder;
+
+ public function __construct(JsonEncoder $jsonEncoder = null)
+ {
+ // Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
+ $this->jsonEncoder = $jsonEncoder ?: new JsonEncoder(
+ new JsonEncode(JsonResponse::DEFAULT_ENCODING_OPTIONS), new JsonDecode(true)
+ );
+ }
+
/**
* {@inheritdoc}
*/
@@ -30,6 +45,14 @@ public function supportsEncoding($format)
return self::FORMAT === $format;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function encode($data, $format, array $context = [])
+ {
+ return $this->jsonEncoder->encode($data, $format, $context);
+ }
+
/**
* {@inheritdoc}
*/
@@ -37,4 +60,12 @@ public function supportsDecoding($format)
{
return self::FORMAT === $format;
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decode($data, $format, array $context = [])
+ {
+ return $this->jsonEncoder->decode($data, $format, $context);
+ }
}
diff --git a/src/Serializer/SerializerContextBuilder.php b/src/Serializer/SerializerContextBuilder.php
new file mode 100644
index 00000000000..36feb767d88
--- /dev/null
+++ b/src/Serializer/SerializerContextBuilder.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Serializer;
+
+use ApiPlatform\Core\Api\RequestAttributesExtractor;
+use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * {@inheritdoc}
+ *
+ * @author Kévin Dunglas
+ */
+final class SerializerContextBuilder implements SerializerContextBuilderInterface
+{
+ private $resourceMetadataFactory;
+
+ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory)
+ {
+ $this->resourceMetadataFactory = $resourceMetadataFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createFromRequest(Request $request, bool $normalization, array $attributes = null) : array
+ {
+ if (null === $attributes) {
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
+ }
+
+ $resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']);
+ $key = $normalization ? 'normalization_context' : 'denormalization_context';
+
+ if (isset($attributes['collection_operation_name'])) {
+ $context = $resourceMetadata->getCollectionOperationAttribute($attributes['collection_operation_name'], $key, [], true);
+ $context['collection_operation_name'] = $attributes['collection_operation_name'];
+ } else {
+ $context = $resourceMetadata->getItemOperationAttribute($attributes['item_operation_name'], $key, [], true);
+ $context['item_operation_name'] = $attributes['item_operation_name'];
+ }
+
+ $context['resource_class'] = $attributes['resource_class'];
+ $context['request_uri'] = $request->getRequestUri();
+
+ return $context;
+ }
+}
diff --git a/src/Serializer/SerializerContextBuilderInterface.php b/src/Serializer/SerializerContextBuilderInterface.php
new file mode 100644
index 00000000000..ea4602f1d1d
--- /dev/null
+++ b/src/Serializer/SerializerContextBuilderInterface.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Serializer;
+
+use ApiPlatform\Core\Exception\RuntimeException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Builds the context used by the Symfony Serializer.
+ *
+ * @author Kévin Dunglas
+ */
+interface SerializerContextBuilderInterface
+{
+ /**
+ * Creates a serialization context from a Request.
+ *
+ * @param Request $request
+ * @param bool $normalization
+ * @param array|null $extractedAttributes
+ *
+ * @throws RuntimeException
+ *
+ * @return array
+ */
+ public function createFromRequest(Request $request, bool $normalization, array $extractedAttributes = null) : array;
+}
diff --git a/tests/Action/GetCollectionActionTest.php b/tests/Action/GetCollectionActionTest.php
index 241b0656674..054cb2dda1f 100644
--- a/tests/Action/GetCollectionActionTest.php
+++ b/tests/Action/GetCollectionActionTest.php
@@ -27,7 +27,7 @@ public function testGetCollection()
$dataProviderProphecy = $this->prophesize(CollectionDataProviderInterface::class);
$dataProviderProphecy->getCollection('Foo', 'get')->willReturn($result);
- $request = new Request([], [], ['_resource_class' => 'Foo', '_collection_operation_name' => 'get', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$action = new GetCollectionAction($dataProviderProphecy->reveal());
$this->assertSame($result, $action($request));
diff --git a/tests/Action/GetItemActionTest.php b/tests/Action/GetItemActionTest.php
index d88c8482b01..c050c4f02ea 100644
--- a/tests/Action/GetItemActionTest.php
+++ b/tests/Action/GetItemActionTest.php
@@ -27,7 +27,7 @@ public function testGetItem()
$dataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class);
$dataProviderProphecy->getItem('Foo', 22, 'get', true)->willReturn($result);
- $request = new Request([], [], ['_resource_class' => 'Foo', '_item_operation_name' => 'get', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$action = new GetItemAction($dataProviderProphecy->reveal());
$this->assertSame($result, $action($request, 22));
@@ -42,7 +42,7 @@ public function testNotFound()
$dataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class);
$dataProviderProphecy->getItem('Foo', 1312, 'get', true)->willReturn(null);
- $request = new Request([], [], ['_resource_class' => 'Foo', '_item_operation_name' => 'get', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$action = new GetItemAction($dataProviderProphecy->reveal());
$action($request, 1312);
diff --git a/tests/Api/RequestAttributesExtractorTest.php b/tests/Api/RequestAttributesExtractorTest.php
index cdf492b9897..dd580143799 100644
--- a/tests/Api/RequestAttributesExtractorTest.php
+++ b/tests/Api/RequestAttributesExtractorTest.php
@@ -21,38 +21,44 @@ class RequestAttributesExtractorTest extends \PHPUnit_Framework_TestCase
{
public function testExtractCollectionAttributes()
{
- $request = new Request([], [], ['_resource_class' => 'Foo', '_collection_operation_name' => 'post', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'post', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$extactor = new RequestAttributesExtractor();
- $this->assertEquals(['Foo', 'post', null, 'json'], $extactor->extractAttributes($request));
+ $this->assertEquals(
+ ['resource_class' => 'Foo', 'format' => 'json', 'mime_type' => 'application/json', 'collection_operation_name' => 'post'],
+ $extactor->extractAttributes($request)
+ );
}
public function testExtractItemAttributes()
{
- $request = new Request([], [], ['_resource_class' => 'Foo', '_item_operation_name' => 'get', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$extactor = new RequestAttributesExtractor();
- $this->assertEquals(['Foo', null, 'get', 'json'], $extactor->extractAttributes($request));
+ $this->assertEquals(
+ ['resource_class' => 'Foo', 'format' => 'json', 'mime_type' => 'application/json', 'item_operation_name' => 'get'],
+ $extactor->extractAttributes($request)
+ );
}
/**
* @expectedException \ApiPlatform\Core\Exception\RuntimeException
- * @expectedExceptionMessage The request attribute "_resource_class" must be defined.
+ * @expectedExceptionMessage The request attribute "_api_resource_class" must be defined.
*/
public function testResourceClassNotSet()
{
- $request = new Request([], [], ['_item_operation_name' => 'get', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_item_operation_name' => 'get', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$extactor = new RequestAttributesExtractor();
$extactor->extractAttributes($request);
}
/**
* @expectedException \ApiPlatform\Core\Exception\RuntimeException
- * @expectedExceptionMessage One of the request attribute "_item_operation_name" or "_collection_operation_name" must be defined.
+ * @expectedExceptionMessage One of the request attribute "_api_collection_operation_name" or "_api_item_operation_name" must be defined.
*/
public function testOperationNotSet()
{
- $request = new Request([], [], ['_resource_class' => 'Foo', '_api_format' => 'json']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_format' => 'json', '_api_mime_type' => 'application/json']);
$extactor = new RequestAttributesExtractor();
$extactor->extractAttributes($request);
}
@@ -63,7 +69,18 @@ public function testOperationNotSet()
*/
public function testFormatNotSet()
{
- $request = new Request([], [], ['_resource_class' => 'Foo', '_collection_operation_name' => 'op']);
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'op']);
+ $extactor = new RequestAttributesExtractor();
+ $extactor->extractAttributes($request);
+ }
+
+ /**
+ * @expectedException \ApiPlatform\Core\Exception\RuntimeException
+ * @expectedExceptionMessage The request attribute "_api_mime_type" must be defined.
+ */
+ public function testMimeTypeNotSet()
+ {
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'op', '_api_format' => 'json']);
$extactor = new RequestAttributesExtractor();
$extactor->extractAttributes($request);
}
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
index 5269694936a..946e9769b41 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
@@ -168,7 +168,7 @@ private function getContainerBuilderProphecy()
$parameters = [
'api_platform.title' => 'title',
'api_platform.description' => 'description',
- 'api_platform.supported_formats' => ['application/ld+json' => 'jsonld'],
+ 'api_platform.formats' => ['application/ld+json' => 'jsonld'],
'api_platform.collection.order' => null,
'api_platform.collection.order_parameter_name' => 'order',
'api_platform.collection.pagination.enabled' => true,
@@ -259,11 +259,14 @@ private function getContainerBuilderProphecy()
'api_platform.routing.resource_path_generator.underscore',
'api_platform.routing.resource_path_generator.dash',
'api_platform.listener.request.format',
- 'api_platform.listener.view.validation',
+ 'api_platform.listener.view.serializer',
'api_platform.listener.view.deserializer',
+ 'api_platform.listener.view.validator',
+ 'api_platform.listener.view.responder',
'api_platform.action.get_collection',
'api_platform.action.post_collection',
'api_platform.action.get_item',
+ 'api_platform.serializer.context_builder',
'api_platform.doctrine.metadata_factory',
'api_platform.doctrine.orm.collection_data_provider',
'api_platform.doctrine.orm.item_data_provider',
@@ -284,10 +287,8 @@ private function getContainerBuilderProphecy()
'api_platform.doctrine.listener.view.manager',
'api_platform.jsonld.entrypoint_builder',
'api_platform.jsonld.context_builder',
- 'api_platform.jsonld.listener.view.responder',
'api_platform.jsonld.normalizer.item',
'api_platform.jsonld.encoder',
- 'api_platform.jsonld.listener.view.responder',
'api_platform.jsonld.action.context',
'api_platform.jsonld.action.entrypoint',
'api_platform.hydra.documentation_builder',
@@ -302,6 +303,7 @@ private function getContainerBuilderProphecy()
'api_platform.hydra.action.documentation',
'api_platform.hydra.action.exception',
];
+
foreach ($definitions as $definition) {
$containerBuilderProphecy->setDefinition($definition, $definitionArgument)->shouldBeCalled();
}
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
index df2f69c0588..4fcf1dd6d41 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
@@ -33,7 +33,7 @@ public function testDefaultConfig()
$this->assertEquals([
'title' => 'title',
'description' => 'description',
- 'supported_formats' => ['jsonld' => ['mime_types' => ['application/ld+json']]],
+ 'formats' => ['jsonld' => ['mime_types' => ['application/ld+json']]],
'routing' => [
'resource_path_generator' => 'api_platform.routing.resource_path_generator.underscore',
],
diff --git a/tests/Bridge/Symfony/Routing/ApiLoaderTest.php b/tests/Bridge/Symfony/Routing/ApiLoaderTest.php
index cb57ea5a2dd..5a4c491a50d 100644
--- a/tests/Bridge/Symfony/Routing/ApiLoaderTest.php
+++ b/tests/Bridge/Symfony/Routing/ApiLoaderTest.php
@@ -98,7 +98,7 @@ public function testNoMethodApiLoader()
'get' => ['method' => 'GET'],
]);
- $routeCollection = $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
+ $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
}
/**
@@ -117,7 +117,7 @@ public function testWrongMethodApiLoader()
'get' => ['method' => 'GET'],
]);
- $routeCollection = $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
+ $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
}
/**
@@ -163,24 +163,14 @@ private function getApiLoaderWithResourceMetadata(ResourceMetadata $resourceMeta
return $apiLoader;
}
- /**
- * get a Route instance with params.
- *
- * @param string path
- * @param string controller
- * @param string ressourceClass
- * @param string operationName
- * @param array methods
- * @param bool collection - whether it's a collection or not
- */
- private function getRoute($path, $controller, $resourceClass, $operationName, array $methods, $collection = false): Route
+ private function getRoute(string $path, string $controller, string $resourceClass, string $operationName, array $methods, bool $collection = false): Route
{
return new Route(
$path,
[
'_controller' => $controller,
- '_resource_class' => $resourceClass,
- sprintf('_%s_operation_name', $collection ? 'collection' : 'item') => $operationName,
+ '_api_resource_class' => $resourceClass,
+ sprintf('_api_%s_operation_name', $collection ? 'collection' : 'item') => $operationName,
],
[],
[],
diff --git a/tests/Bridge/Symfony/Routing/IriConverterTest.php b/tests/Bridge/Symfony/Routing/IriConverterTest.php
index e21b8afcb92..1c89152764b 100644
--- a/tests/Bridge/Symfony/Routing/IriConverterTest.php
+++ b/tests/Bridge/Symfony/Routing/IriConverterTest.php
@@ -80,7 +80,7 @@ public function testGetItemFromIriItemNotFoundException()
$routerMock = $this->prophesize(RouterInterface::class);
$routerMock->match('/users/3')->willReturn([
- '_resource_class' => 'AppBundle\Entity\User',
+ '_api_resource_class' => 'AppBundle\Entity\User',
'id' => 3,
])->shouldBeCalledTimes(1);
$itemDataProviderMock->getItem('AppBundle\Entity\User', 3, null, false)->shouldBeCalledTimes(1);
@@ -102,7 +102,7 @@ public function testGetItemFromIri()
$routerMock = $this->prophesize(RouterInterface::class);
$routerMock->match('/users/3')->willReturn([
- '_resource_class' => 'AppBundle\Entity\User',
+ '_api_resource_class' => 'AppBundle\Entity\User',
'id' => 3,
])->shouldBeCalledTimes(1);
$itemDataProviderMock->getItem('AppBundle\Entity\User', 3, null, true)
diff --git a/tests/Bridge/Symfony/Validator/EventListener/ViewListenerTest.php b/tests/Bridge/Symfony/Validator/EventListener/ValidatorViewListenerTest.php
similarity index 78%
rename from tests/Bridge/Symfony/Validator/EventListener/ViewListenerTest.php
rename to tests/Bridge/Symfony/Validator/EventListener/ValidatorViewListenerTest.php
index f5bf2ff368a..6a3664340b5 100644
--- a/tests/Bridge/Symfony/Validator/EventListener/ViewListenerTest.php
+++ b/tests/Bridge/Symfony/Validator/EventListener/ValidatorViewListenerTest.php
@@ -11,7 +11,7 @@
namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\EventListener;
-use ApiPlatform\Core\Bridge\Symfony\Validator\EventListener\ViewListener;
+use ApiPlatform\Core\Bridge\Symfony\Validator\EventListener\ValidatorViewListener;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use ApiPlatform\Core\Tests\Fixtures\DummyEntity;
@@ -19,24 +19,25 @@
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* @author Samuel ROZE
*/
-class ViewListenerTest extends \PHPUnit_Framework_TestCase
+class ValidatorViewListenerTest extends \PHPUnit_Framework_TestCase
{
public function testValidatorIsCalled()
{
$data = new DummyEntity();
$expectedValidationGroups = ['a', 'b', 'c'];
- $validatorProphecy = $this->prophesize('Symfony\Component\Validator\Validator\ValidatorInterface');
+ $validatorProphecy = $this->prophesize(ValidatorInterface::class);
$validatorProphecy->validate($data, null, $expectedValidationGroups)->shouldBeCalled();
$validator = $validatorProphecy->reveal();
list($resourceMetadataFactory, $event) = $this->createEventObject($expectedValidationGroups, $data);
- $validationViewListener = new ViewListener($resourceMetadataFactory, $validator);
+ $validationViewListener = new ValidatorViewListener($validator, $resourceMetadataFactory);
$validationViewListener->onKernelView($event);
}
@@ -52,13 +53,13 @@ public function testThrowsValidationExceptionWithViolationsFound()
$violationsProphecy->count()->willReturn(1);
$violations = $violationsProphecy->reveal();
- $validatorProphecy = $this->prophesize('Symfony\Component\Validator\Validator\ValidatorInterface');
+ $validatorProphecy = $this->prophesize(ValidatorInterface::class);
$validatorProphecy->validate($data, null, $expectedValidationGroups)->shouldBeCalled()->willReturn($violations);
$validator = $validatorProphecy->reveal();
list($resourceMetadataFactory, $event) = $this->createEventObject($expectedValidationGroups, $data);
- $validationViewListener = new ViewListener($resourceMetadataFactory, $validator);
+ $validationViewListener = new ValidatorViewListener($validator, $resourceMetadataFactory);
$validationViewListener->onKernelView($event);
}
@@ -80,10 +81,12 @@ private function createEventObject($expectedValidationGroups, $data)
$resourceMetadataFactoryProphecy->create(DummyEntity::class)->willReturn($resourceMetadata);
$resourceMetadataFactory = $resourceMetadataFactoryProphecy->reveal();
- $kernel = $this->prophesize('Symfony\Component\HttpKernel\HttpKernelInterface')->reveal();
+ $kernel = $this->prophesize(HttpKernelInterface::class)->reveal();
$request = new Request([], [], [
- '_resource_class' => DummyEntity::class,
- '_item_operation_name' => 'create',
+ '_api_resource_class' => DummyEntity::class,
+ '_api_item_operation_name' => 'create',
+ '_api_format' => 'json',
+ '_api_mime_type' => 'application/json',
]);
$request->setMethod(Request::METHOD_POST);
diff --git a/tests/EventListener/DeserializerViewListenerTest.php b/tests/EventListener/DeserializerViewListenerTest.php
index 03333f8a7d4..0bf0c1393f8 100644
--- a/tests/EventListener/DeserializerViewListenerTest.php
+++ b/tests/EventListener/DeserializerViewListenerTest.php
@@ -12,6 +12,7 @@
namespace ApiPlatform\Core\Tests\EventListener;
use ApiPlatform\Core\EventListener\DeserializerViewListener;
+use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use Prophecy\Argument;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -36,7 +37,10 @@ public function testDoNotCallWhenAResponse()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->deserialize()->shouldNotBeCalled();
- $listener = new DeserializerViewListener($serializerProphecy->reveal());
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new DeserializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
$listener->onKernelView($eventProphecy->reveal());
}
@@ -53,7 +57,10 @@ public function testDoNotCallWhenRequestMethodIsSafe()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->deserialize()->shouldNotBeCalled();
- $listener = new DeserializerViewListener($serializerProphecy->reveal());
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new DeserializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
$listener->onKernelView($eventProphecy->reveal());
}
@@ -70,34 +77,40 @@ public function testDoNotCallWhenRequestNotManaged()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->deserialize()->shouldNotBeCalled();
- $listener = new DeserializerViewListener($serializerProphecy->reveal());
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new DeserializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
$listener->onKernelView($eventProphecy->reveal());
}
/**
* @dataProvider methodProvider
*/
- public function testDeserialize($method)
+ public function testDeserialize(string $method, bool $populateObject)
{
- $result = new \stdClass();
-
+ $result = $populateObject ? new \stdClass() : null;
$eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
- $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getControllerResult()->willReturn($result);
$eventProphecy->setControllerResult($result)->shouldBeCalled();
- $request = new Request([], [], ['_resource_class' => 'Foo', '_collection_operation_name' => 'post', '_api_format' => 'json'], [], [], [], '{}');
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'post', '_api_format' => 'json', '_api_mime_type' => 'application/json'], [], [], [], '{}');
$request->setMethod($method);
$eventProphecy->getRequest()->willReturn($request);
$serializerProphecy = $this->prophesize(SerializerInterface::class);
- $serializerProphecy->deserialize('{}', 'Foo', 'json', Argument::type('array'))->willReturn($result);
+ $context = $populateObject ? ['object_to_populate' => $populateObject] : [];
+ $serializerProphecy->deserialize('{}', 'Foo', 'json', $context)->willReturn($result);
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->willReturn([]);
- $listener = new DeserializerViewListener($serializerProphecy->reveal());
+ $listener = new DeserializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
$listener->onKernelView($eventProphecy->reveal());
}
public function methodProvider()
{
- return [[Request::METHOD_POST], [Request::METHOD_PUT]];
+ return [[Request::METHOD_POST, false], [Request::METHOD_PUT, true]];
}
}
diff --git a/tests/EventListener/FormatRequestListenerTest.php b/tests/EventListener/FormatRequestListenerTest.php
index 7c8356fa953..477259b97a3 100644
--- a/tests/EventListener/FormatRequestListenerTest.php
+++ b/tests/EventListener/FormatRequestListenerTest.php
@@ -33,12 +33,13 @@ public function testNoResourceClass()
$listener->onKernelRequest($event);
$this->assertFalse($request->attributes->has('_api_format'));
+ $this->assertFalse($request->attributes->has('_api_mime_type'));
}
public function testSupportedRequestFormat()
{
$request = new Request();
- $request->attributes->set('_resource_class', 'Foo');
+ $request->attributes->set('_api_resource_class', 'Foo');
$request->setRequestFormat('xml');
$eventProphecy = $this->prophesize(GetResponseEvent::class);
@@ -49,12 +50,13 @@ public function testSupportedRequestFormat()
$listener->onKernelRequest($event);
$this->assertSame('xml', $request->attributes->get('_api_format'));
+ $this->assertSame('text/xml', $request->attributes->get('_api_mime_type'));
}
public function testUnsupportedRequestFormat()
{
$request = new Request();
- $request->attributes->set('_resource_class', 'Foo');
+ $request->attributes->set('_api_resource_class', 'Foo');
$request->setRequestFormat('xml');
$eventProphecy = $this->prophesize(GetResponseEvent::class);
@@ -65,12 +67,13 @@ public function testUnsupportedRequestFormat()
$listener->onKernelRequest($event);
$this->assertSame('json', $request->attributes->get('_api_format'));
+ $this->assertSame('application/json', $request->attributes->get('_api_mime_type'));
}
public function testSupportedAcceptHeader()
{
$request = new Request();
- $request->attributes->set('_resource_class', 'Foo');
+ $request->attributes->set('_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);
@@ -81,12 +84,13 @@ public function testSupportedAcceptHeader()
$listener->onKernelRequest($event);
$this->assertSame('json', $request->attributes->get('_api_format'));
+ $this->assertSame('application/json', $request->attributes->get('_api_mime_type'));
}
public function testUnsupportedAcceptHeader()
{
$request = new Request();
- $request->attributes->set('_resource_class', 'Foo');
+ $request->attributes->set('_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);
@@ -97,5 +101,6 @@ public function testUnsupportedAcceptHeader()
$listener->onKernelRequest($event);
$this->assertSame('binary', $request->attributes->get('_api_format'));
+ $this->assertSame('application/octet-stream', $request->attributes->get('_api_mime_type'));
}
}
diff --git a/tests/EventListener/ResponderViewListenerTest.php b/tests/EventListener/ResponderViewListenerTest.php
new file mode 100644
index 00000000000..d91d078efea
--- /dev/null
+++ b/tests/EventListener/ResponderViewListenerTest.php
@@ -0,0 +1,109 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Tests\EventListener;
+
+use ApiPlatform\Core\EventListener\ResponderViewListener;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * @author Kévin Dunglas
+ */
+class ResponderViewListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDoNotHandleResponse()
+ {
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new Response());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_mime_type' => 'text/xml']));
+
+ $listener = new ResponderViewListener();
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testDoNotHandleWhenMimeTypeNotSet()
+ {
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn('foo');
+ $eventProphecy->getRequest()->willReturn(new Request());
+
+ $listener = new ResponderViewListener();
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testCreate200Response()
+ {
+ $kernelProphecy = $this->prophesize(HttpKernelInterface::class);
+ $event = new GetResponseForControllerResultEvent(
+ $kernelProphecy->reveal(),
+ new Request([], [], ['_api_mime_type' => 'text/xml']),
+ HttpKernelInterface::MASTER_REQUEST,
+ 'foo'
+ );
+
+ $listener = new ResponderViewListener();
+ $listener->onKernelView($event);
+
+ $response = $event->getResponse();
+ $this->assertEquals('foo', $response->getContent());
+ $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
+ $this->assertEquals('text/xml', $response->headers->get('Content-Type'));
+ }
+
+ public function testCreate201Response()
+ {
+ $kernelProphecy = $this->prophesize(HttpKernelInterface::class);
+
+ $request = new Request([], [], ['_api_mime_type' => 'text/xml']);
+ $request->setMethod(Request::METHOD_POST);
+
+ $event = new GetResponseForControllerResultEvent(
+ $kernelProphecy->reveal(),
+ $request,
+ HttpKernelInterface::MASTER_REQUEST,
+ 'foo'
+ );
+
+ $listener = new ResponderViewListener();
+ $listener->onKernelView($event);
+
+ $response = $event->getResponse();
+ $this->assertEquals('foo', $response->getContent());
+ $this->assertEquals(Response::HTTP_CREATED, $response->getStatusCode());
+ $this->assertEquals('text/xml', $response->headers->get('Content-Type'));
+ }
+
+ public function testCreate204Response()
+ {
+ $kernelProphecy = $this->prophesize(HttpKernelInterface::class);
+
+ $request = new Request([], [], ['_api_mime_type' => 'text/xml']);
+ $request->setMethod(Request::METHOD_DELETE);
+
+ $event = new GetResponseForControllerResultEvent(
+ $kernelProphecy->reveal(),
+ $request,
+ HttpKernelInterface::MASTER_REQUEST,
+ 'foo'
+ );
+
+ $listener = new ResponderViewListener();
+ $listener->onKernelView($event);
+
+ $response = $event->getResponse();
+ $this->assertEquals('foo', $response->getContent());
+ $this->assertEquals(Response::HTTP_NO_CONTENT, $response->getStatusCode());
+ $this->assertEquals('text/xml', $response->headers->get('Content-Type'));
+ }
+}
diff --git a/tests/EventListener/SerializerViewListenerTest.php b/tests/EventListener/SerializerViewListenerTest.php
new file mode 100644
index 00000000000..c4e47b45daf
--- /dev/null
+++ b/tests/EventListener/SerializerViewListenerTest.php
@@ -0,0 +1,126 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Tests\EventListener;
+
+use ApiPlatform\Core\EventListener\SerializerViewListener;
+use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
+use Prophecy\Argument;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * @author Kévin Dunglas
+ */
+class SerializerViewListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDoNotSerializeResponse()
+ {
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), Argument::type('array'))->shouldNotBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new Response());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_format' => 'xml']));
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testDoNotSerializeWhenFormatNotSet()
+ {
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), Argument::type('array'))->shouldNotBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getRequest()->willReturn(new Request());
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testDoNotSerializeWhenResourceClassNotSet()
+ {
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), Argument::type('array'))->shouldNotBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_format' => 'xml', '_api_mime_type' => 'text/xml', '_api_collection_operation_name' => 'get']));
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testDoNotSerializeWhenOperationNotSet()
+ {
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), Argument::type('array'))->shouldNotBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_format' => 'xml', '_api_mime_type' => 'text/xml', '_api_resource_class' => 'Foo']));
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), false, Argument::type('array'))->shouldNotBeCalled();
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testSerializeCollectionOperation()
+ {
+ $expectedContext = ['request_uri' => '', 'resource_class' => 'Foo', 'collection_operation_name' => 'get'];
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), $expectedContext)->willReturn('bar')->shouldBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_format' => 'xml', '_api_mime_type' => 'text/xml', '_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']));
+ $eventProphecy->setControllerResult('bar')->shouldBeCalled();
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext);
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+
+ public function testSerializeItemOperation()
+ {
+ $expectedContext = ['request_uri' => '', 'resource_class' => 'Foo', 'item_operation_name' => 'get'];
+ $serializerProphecy = $this->prophesize(SerializerInterface::class);
+ $serializerProphecy->serialize(Argument::any(), Argument::type('string'), $expectedContext)->willReturn('bar')->shouldBeCalled();
+
+ $eventProphecy = $this->prophesize(GetResponseForControllerResultEvent::class);
+ $eventProphecy->getControllerResult()->willReturn(new \stdClass());
+ $eventProphecy->getRequest()->willReturn(new Request([], [], ['_api_format' => 'xml', '_api_mime_type' => 'text/xml', '_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get']));
+ $eventProphecy->setControllerResult('bar')->shouldBeCalled();
+
+ $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class);
+ $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext);
+
+ $listener = new SerializerViewListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal());
+ $listener->onKernelView($eventProphecy->reveal());
+ }
+}
diff --git a/tests/Fixtures/TestBundle/Controller/ConfigCustomController.php b/tests/Fixtures/TestBundle/Controller/ConfigCustomController.php
index 808f0a10613..430058a7450 100644
--- a/tests/Fixtures/TestBundle/Controller/ConfigCustomController.php
+++ b/tests/Fixtures/TestBundle/Controller/ConfigCustomController.php
@@ -22,9 +22,6 @@
*/
class ConfigCustomController
{
- /**
- * @var DataProviderInterface
- */
private $dataProvider;
public function __construct(ItemDataProviderInterface $dataProvider)
@@ -34,8 +31,8 @@ public function __construct(ItemDataProviderInterface $dataProvider)
public function __invoke(Request $request, $id)
{
- list($resourceType) = RequestAttributesExtractor::extractAttributes($request);
+ $attributes = RequestAttributesExtractor::extractAttributes($request);
- return $this->dataProvider->getItem($resourceType, $id);
+ return $this->dataProvider->getItem($attributes['resource_class'], $id);
}
}
diff --git a/tests/Fixtures/TestBundle/Controller/CustomController.php b/tests/Fixtures/TestBundle/Controller/CustomController.php
index 1dea8cc0ace..2714ddc2c11 100644
--- a/tests/Fixtures/TestBundle/Controller/CustomController.php
+++ b/tests/Fixtures/TestBundle/Controller/CustomController.php
@@ -11,8 +11,8 @@
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller;
-use ApiPlatform\Core\JsonLd\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Custom Controller.
@@ -21,11 +21,8 @@
*/
class CustomController extends Controller
{
- /**
- * @return \ApiPlatform\Core\JsonLd\Response
- */
- public function customAction($id)
+ public function customAction(int $id) : JsonResponse
{
- return new Response(sprintf('This is a custom action for %d.', $id));
+ return new JsonResponse(sprintf('This is a custom action for %d.', $id), 200, ['Content-Type' => 'application/ld+json']);
}
}
diff --git a/tests/Fixtures/TestBundle/Entity/AbstractDummy.php b/tests/Fixtures/TestBundle/Entity/AbstractDummy.php
index 9c975e83d6d..0799318e01b 100644
--- a/tests/Fixtures/TestBundle/Entity/AbstractDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/AbstractDummy.php
@@ -18,7 +18,7 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * AbstractDummy.
+ * Abstract Dummy.
*
* @author Jérémy Derussé
*
diff --git a/tests/Fixtures/TestBundle/Entity/CompositeItem.php b/tests/Fixtures/TestBundle/Entity/CompositeItem.php
index 7a7eba082b4..29531207fbd 100644
--- a/tests/Fixtures/TestBundle/Entity/CompositeItem.php
+++ b/tests/Fixtures/TestBundle/Entity/CompositeItem.php
@@ -16,6 +16,8 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
+ * Composite Item.
+ *
* @ApiResource
* @ORM\Entity
*/
diff --git a/tests/Fixtures/TestBundle/Entity/CompositeLabel.php b/tests/Fixtures/TestBundle/Entity/CompositeLabel.php
index 557fa3d5b81..d126743afca 100644
--- a/tests/Fixtures/TestBundle/Entity/CompositeLabel.php
+++ b/tests/Fixtures/TestBundle/Entity/CompositeLabel.php
@@ -16,8 +16,10 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
- * @ORM\Entity
+ * Composite Label.
+ *
* @ApiResource
+ * @ORM\Entity
*/
class CompositeLabel
{
diff --git a/tests/Fixtures/TestBundle/Entity/CompositeRelation.php b/tests/Fixtures/TestBundle/Entity/CompositeRelation.php
index feb8578bb9f..26cb1348a99 100644
--- a/tests/Fixtures/TestBundle/Entity/CompositeRelation.php
+++ b/tests/Fixtures/TestBundle/Entity/CompositeRelation.php
@@ -16,8 +16,10 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
- * @ORM\Entity
+ * Composite Relation.
+ *
* @ApiResource
+ * @ORM\Entity
*/
class CompositeRelation
{
diff --git a/tests/Fixtures/TestBundle/Entity/ConcreteDummy.php b/tests/Fixtures/TestBundle/Entity/ConcreteDummy.php
index 422ed50705f..d640cb72bdd 100644
--- a/tests/Fixtures/TestBundle/Entity/ConcreteDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/ConcreteDummy.php
@@ -16,7 +16,7 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * ConcreteDummy.
+ * Concrete Dummy.
*
* @author Jérémy Derusse
*
diff --git a/tests/Fixtures/TestBundle/Entity/CustomIdentifierDummy.php b/tests/Fixtures/TestBundle/Entity/CustomIdentifierDummy.php
index a6af6dd6e33..36f981dff70 100644
--- a/tests/Fixtures/TestBundle/Entity/CustomIdentifierDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/CustomIdentifierDummy.php
@@ -15,7 +15,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * Custom identifier dummy.
+ * Custom Identifier Dummy.
*
* @ApiResource
* @ORM\Entity
diff --git a/tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php b/tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php
index df508b049fc..dd72f8cc042 100644
--- a/tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/CustomNormalizedDummy.php
@@ -18,7 +18,7 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * Custom normalized dummy.
+ * Custom Normalized Dummy.
*
* @author Mikaël Labrut
*
diff --git a/tests/Fixtures/TestBundle/Entity/CustomWritableIdentifierDummy.php b/tests/Fixtures/TestBundle/Entity/CustomWritableIdentifierDummy.php
index 8df16eb22cf..1185f0bc9d8 100644
--- a/tests/Fixtures/TestBundle/Entity/CustomWritableIdentifierDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/CustomWritableIdentifierDummy.php
@@ -15,7 +15,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * Custom writable identifier dummy.
+ * Custom Writable Identifier Dummy.
*
* @ApiResource
* @ORM\Entity
diff --git a/tests/Fixtures/TestBundle/Entity/DummyFriend.php b/tests/Fixtures/TestBundle/Entity/DummyFriend.php
index 6bfe36e0c5b..901929911c7 100644
--- a/tests/Fixtures/TestBundle/Entity/DummyFriend.php
+++ b/tests/Fixtures/TestBundle/Entity/DummyFriend.php
@@ -18,11 +18,11 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * DummyFriend.
+ * Dummy Friend.
*
* @author Kévin Dunglas
*
- * @ApiResource()
+ * @ApiResource
* @ORM\Entity
*/
class DummyFriend
diff --git a/tests/Fixtures/TestBundle/Entity/FileConfigDummy.php b/tests/Fixtures/TestBundle/Entity/FileConfigDummy.php
index fb401e952f5..f6f7b876914 100644
--- a/tests/Fixtures/TestBundle/Entity/FileConfigDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/FileConfigDummy.php
@@ -14,7 +14,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * FileConfigDummy.
+ * File Config Dummy.
*
* @ORM\Entity
*/
diff --git a/tests/Fixtures/TestBundle/Entity/NoCollectionDummy.php b/tests/Fixtures/TestBundle/Entity/NoCollectionDummy.php
index b1dc6c69b23..1c96c9016d0 100644
--- a/tests/Fixtures/TestBundle/Entity/NoCollectionDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/NoCollectionDummy.php
@@ -15,7 +15,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * No collection dummy.
+ * No Collection Dummy.
*
* @ApiResource(collectionOperations={})
* @ORM\Entity
diff --git a/tests/Fixtures/TestBundle/Entity/CustomAttributeDummy.php b/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php
similarity index 63%
rename from tests/Fixtures/TestBundle/Entity/CustomAttributeDummy.php
rename to tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php
index 942d2b5a25a..890bba60a5b 100644
--- a/tests/Fixtures/TestBundle/Entity/CustomAttributeDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/OverriddenOperationDummy.php
@@ -18,29 +18,32 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * Custom Attribute Dummy.
+ * Overridden Operation Dummy.
*
* @author Amrouche Hamza
*
- * @ApiResource(attributes={
- * "normalization_context"={"groups"={"custom_attr_dummy_read"}},
- * "denormalization_context"={"groups"={"custom_attr_dummy_write"}}
- * },
- * itemOperations={
- * "get"={"method"="GET",
- * "normalization_context"={"groups"={"custom_attr_dummy_get"}},
- * "denormalization_context"={"groups"={"custom_attr_dummy_get"}}
- * },
- * "put"={"method"="PUT",
- * "normalization_context"={"groups"={"custom_attr_dummy_put"}},
- * "denormalization_context"={"groups"={"custom_attr_dummy_put"}}
+ * @ApiResource(
+ * attributes={
+ * "normalization_context"={"groups"={"overridden_operation_dummy_read"}},
+ * "denormalization_context"={"groups"={"overridden_operation_dummy_write"}}
* },
+ * itemOperations={
+ * "get"={
+ * "method"="GET",
+ * "normalization_context"={"groups"={"overridden_operation_dummy_get"}},
+ * "denormalization_context"={"groups"={"overridden_operation_dummy_get"}}
+ * },
+ * "put"={
+ * "method"="PUT",
+ * "normalization_context"={"groups"={"overridden_operation_dummy_put"}},
+ * "denormalization_context"={"groups"={"overridden_operation_dummy_put"}}
+ * },
* "delete"={"method"="DELETE"}
- * },
+ * }
* )
* @ORM\Entity
*/
-class CustomAttributeDummy
+class OverriddenOperationDummy
{
/**
* @var int The id.
@@ -56,7 +59,7 @@ class CustomAttributeDummy
*
* @ORM\Column
* @Assert\NotBlank
- * @Groups({"custom_attr_dummy_read", "custom_attr_dummy_write", "custom_attr_dummy_get"})
+ * @Groups({"overridden_operation_dummy_read", "overridden_operation_dummy_write", "overridden_operation_dummy_get"})
* @ApiProperty(iri="http://schema.org/name")
*/
private $name;
@@ -65,7 +68,7 @@ class CustomAttributeDummy
* @var string The dummy name alias.
*
* @ORM\Column(nullable=true)
- * @Groups({"custom_attr_dummy_read", "custom_attr_dummy_put", "custom_attr_dummy_get"})
+ * @Groups({"overridden_operation_dummy_read", "overridden_operation_dummy_put", "overridden_operation_dummy_get"})
* @ApiProperty(iri="https://schema.org/alternateName")
*/
private $alias;
@@ -74,17 +77,14 @@ class CustomAttributeDummy
* @var string A short description of the item.
*
* @ORM\Column(nullable=true)
- * @Groups({"custom_attr_dummy_read" ,"custom_attr_dummy_write", "custom_attr_dummy_get", "custom_attr_dummy_put"})
+ * @Groups({"overridden_operation_dummy_read" ,"overridden_operation_dummy_write", "overridden_operation_dummy_get", "overridden_operation_dummy_put"})
* @ApiProperty(iri="https://schema.org/description")
*/
public $description;
/**
- * @var string A short description of the item.
- *
* @ORM\Column(nullable=true)
- * @Groups({"custom_attr_dummy_write"})
- * @ApiProperty(iri="https://schema.org/description")
+ * @Groups({"overridden_operation_dummy_write"})
*/
public $notGettable;
diff --git a/tests/Fixtures/TestBundle/Entity/ParentDummy.php b/tests/Fixtures/TestBundle/Entity/ParentDummy.php
index c52aa5cff8b..5ebcceee66a 100644
--- a/tests/Fixtures/TestBundle/Entity/ParentDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/ParentDummy.php
@@ -14,7 +14,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * Parent dummy.
+ * Parent Dummy.
*
* @author Kévin Dunglas
*
diff --git a/tests/Fixtures/TestBundle/Entity/RelatedDummy.php b/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
index ff1789dd668..ea42412c2da 100644
--- a/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
@@ -17,7 +17,7 @@
use Symfony\Component\Validator\Constraints as Assert;
/**
- * Related dummy.
+ * Related Dummy.
*
* @author Kévin Dunglas
*
diff --git a/tests/Fixtures/TestBundle/Entity/RelatedToDummyFriend.php b/tests/Fixtures/TestBundle/Entity/RelatedToDummyFriend.php
index ef432b45bc2..11dfaf4fcc1 100644
--- a/tests/Fixtures/TestBundle/Entity/RelatedToDummyFriend.php
+++ b/tests/Fixtures/TestBundle/Entity/RelatedToDummyFriend.php
@@ -61,9 +61,9 @@ public function getName()
}
/**
- * Get dummyFriend.
+ * Gets dummyFriend.
*
- * @return dummyFriend.
+ * @return DummyFriend
*/
public function getDummyFriend()
{
@@ -71,9 +71,9 @@ public function getDummyFriend()
}
/**
- * Set dummyFriend.
+ * Sets dummyFriend.
*
- * @param dummyFriend the value to set.
+ * @param $dummyFriend the value to set.
*/
public function setDummyFriend($dummyFriend)
{
@@ -81,9 +81,9 @@ public function setDummyFriend($dummyFriend)
}
/**
- * Get relatedDummy.
+ * Gets relatedDummy.
*
- * @return relatedDummy.
+ * @return RelatedDummy
*/
public function getRelatedDummy()
{
@@ -91,9 +91,9 @@ public function getRelatedDummy()
}
/**
- * Set relatedDummy.
+ * Sets relatedDummy.
*
- * @param relatedDummy the value to set.
+ * @param $relatedDummy the value to set.
*/
public function setRelatedDummy($relatedDummy)
{
diff --git a/tests/Fixtures/TestBundle/Entity/RelationEmbedder.php b/tests/Fixtures/TestBundle/Entity/RelationEmbedder.php
index 54283f860a2..21d89825ea6 100644
--- a/tests/Fixtures/TestBundle/Entity/RelationEmbedder.php
+++ b/tests/Fixtures/TestBundle/Entity/RelationEmbedder.php
@@ -16,7 +16,7 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
- * Relation embedder.
+ * Relation Embedder.
*
* @author Kévin Dunglas
*
diff --git a/tests/Fixtures/TestBundle/Entity/SingleFileConfigDummy.php b/tests/Fixtures/TestBundle/Entity/SingleFileConfigDummy.php
index 72ee7b9b336..e2ab788122b 100644
--- a/tests/Fixtures/TestBundle/Entity/SingleFileConfigDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/SingleFileConfigDummy.php
@@ -14,7 +14,7 @@
use Doctrine\ORM\Mapping as ORM;
/**
- * FileConfigDummy.
+ * File Config Dummy.
*
* @ORM\Entity
*/
diff --git a/tests/Fixtures/TestBundle/Entity/ThirdLevel.php b/tests/Fixtures/TestBundle/Entity/ThirdLevel.php
index ace5e49a6de..da5a6d70fbf 100644
--- a/tests/Fixtures/TestBundle/Entity/ThirdLevel.php
+++ b/tests/Fixtures/TestBundle/Entity/ThirdLevel.php
@@ -16,7 +16,7 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
- * ThirdLevel.
+ * Third Level.
*
* @author Kévin Dunglas
*
diff --git a/tests/Fixtures/TestBundle/Entity/User.php b/tests/Fixtures/TestBundle/Entity/User.php
index 9c9faedfb4d..14b4512991e 100644
--- a/tests/Fixtures/TestBundle/Entity/User.php
+++ b/tests/Fixtures/TestBundle/Entity/User.php
@@ -18,6 +18,8 @@
use Symfony\Component\Serializer\Annotation\Groups;
/**
+ * A User.
+ *
* @ORM\Entity
* @ApiResource(attributes={
* "normalization_context"={"groups"={"user", "user-read"}},
diff --git a/tests/Fixtures/TestBundle/EventListener/XmlResponderViewListener.php b/tests/Fixtures/TestBundle/EventListener/XmlResponderViewListener.php
deleted file mode 100644
index efa75bf0c14..00000000000
--- a/tests/Fixtures/TestBundle/EventListener/XmlResponderViewListener.php
+++ /dev/null
@@ -1,93 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\EventListener;
-
-use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
-use Symfony\Component\Serializer\SerializerInterface;
-
-/**
- * Serializes data in XML then builds the response object.
- *
- * @author Kévin Dunglas
- */
-class XmlResponderViewListener
-{
- const FORMAT = 'xml';
-
- /**
- * @var SerializerInterface
- */
- private $serializer;
-
- /**
- * @var ResourceMetadataFactoryInterface
- */
- private $resourceMetadataFactory;
-
- public function __construct(SerializerInterface $serializer, ResourceMetadataFactoryInterface $resourceMetadataFactory)
- {
- $this->serializer = $serializer;
- $this->resourceMetadataFactory = $resourceMetadataFactory;
- }
-
- /**
- * In an API context, converts any data to a XML response.
- *
- * @param GetResponseForControllerResultEvent $event
- *
- * @return Response|mixed
- */
- public function onKernelView(GetResponseForControllerResultEvent $event)
- {
- $controllerResult = $event->getControllerResult();
-
- if ($controllerResult instanceof Response) {
- return $controllerResult;
- }
-
- $request = $event->getRequest();
-
- $format = $request->attributes->get('_api_format');
- if (self::FORMAT !== $format) {
- return $controllerResult;
- }
-
- switch ($request->getMethod()) {
- case Request::METHOD_POST:
- $status = 201;
- break;
-
- case Request::METHOD_DELETE:
- $status = 204;
- break;
-
- default:
- $status = 200;
- break;
- }
-
- $resourceClass = $request->attributes->get('_resource_class');
- $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
- $context = $resourceMetadata->getAttribute('normalization_context', []);
-
- $response = new Response(
- $this->serializer->serialize($controllerResult, self::FORMAT, $context),
- $status,
- ['Content-Type' => 'application/xml']
- );
-
- $event->setResponse($response);
- }
-}
diff --git a/tests/Fixtures/app/config/config.yml b/tests/Fixtures/app/config/config.yml
index 782b3cb1e4a..173bf393ef4 100644
--- a/tests/Fixtures/app/config/config.yml
+++ b/tests/Fixtures/app/config/config.yml
@@ -29,9 +29,10 @@ doctrine:
api_platform:
title: 'My Dummy API'
description: 'This is a test API.'
- supported_formats:
+ formats:
jsonld: ['application/ld+json']
xml: ['application/xml', 'text/xml']
+ json: ['application/json']
name_converter: 'app.name_converter'
enable_fos_user: true
collection:
@@ -65,15 +66,6 @@ services:
app.name_converter:
class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\Serializer\NameConverter\CustomConverter'
- app.xml_responder_view_listener:
- class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\EventListener\XmlResponderViewListener'
- arguments:
- - '@api_platform.serializer'
-
- - '@api_platform.metadata.resource.metadata_factory'
- tags:
- - { name: 'kernel.event_listener', event: 'kernel.view', method: 'onKernelView' }
-
app.my_dummy_resource.search_filter:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', 'alias': 'start', 'description': 'word_start', 'relatedDummy.name': 'exact', 'relatedDummies': 'exact', 'dummy': 'ipartial' } ]
diff --git a/tests/JsonLd/Serializer/JsonLdEncoderTest.php b/tests/JsonLd/Serializer/JsonLdEncoderTest.php
new file mode 100644
index 00000000000..bd667a19215
--- /dev/null
+++ b/tests/JsonLd/Serializer/JsonLdEncoderTest.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Tests\JsonLd\Serializer;
+
+use ApiPlatform\Core\JsonLd\Serializer\JsonLdEncoder;
+
+/**
+ * @author Kévin Dunglas
+ */
+class JsonLdEncoderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var JsonLdEncoder
+ */
+ private $encoder;
+
+ public function setUp()
+ {
+ $this->encoder = new JsonLdEncoder();
+ }
+
+ public function testSupportEncoding()
+ {
+ $this->assertTrue($this->encoder->supportsEncoding(JsonLdEncoder::FORMAT));
+ $this->assertFalse($this->encoder->supportsEncoding('csv'));
+ }
+
+ public function testEncode()
+ {
+ $data = ['foo' => 'bar'];
+
+ $this->assertEquals('{"foo":"bar"}', $this->encoder->encode($data, JsonLdEncoder::FORMAT));
+ }
+
+ public function testSupportDecoding()
+ {
+ $this->assertTrue($this->encoder->supportsDecoding(JsonLdEncoder::FORMAT));
+ $this->assertFalse($this->encoder->supportsDecoding('csv'));
+ }
+
+ public function testDecode()
+ {
+ $this->assertEquals(['foo' => 'bar'], $this->encoder->decode('{"foo":"bar"}', JsonLdEncoder::FORMAT));
+ }
+}
diff --git a/tests/Serializer/SerializerContextBuilderTest.php b/tests/Serializer/SerializerContextBuilderTest.php
new file mode 100644
index 00000000000..e3eef1a7d19
--- /dev/null
+++ b/tests/Serializer/SerializerContextBuilderTest.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ApiPlatform\Core\Tests\Serializer;
+
+use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
+use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
+use ApiPlatform\Core\Serializer\SerializerContextBuilder;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @author Kévin Dunglas
+ */
+class SerializerContextBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var SerializerContextBuilder
+ */
+ private $builder;
+
+ protected function setUp()
+ {
+ $resourceMetadata = new ResourceMetadata(
+ null,
+ null,
+ null,
+ [],
+ [],
+ ['normalization_context' => ['foo' => 'bar'], 'denormalization_context' => ['bar' => 'baz']]
+ );
+
+ $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
+ $resourceMetadataFactoryProphecy->create('Foo')->willReturn($resourceMetadata);
+
+ $this->builder = new SerializerContextBuilder($resourceMetadataFactoryProphecy->reveal());
+ }
+
+ public function testCreateFromRequest()
+ {
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get', '_api_format' => 'xml', '_api_mime_type' => 'text/xml']);
+ $expected = ['foo' => 'bar', 'item_operation_name' => 'get', 'resource_class' => 'Foo', 'request_uri' => ''];
+ $this->assertEquals($expected, $this->builder->createFromRequest($request, true));
+
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'pot', '_api_format' => 'xml', '_api_mime_type' => 'text/xml']);
+ $expected = ['foo' => 'bar', 'collection_operation_name' => 'pot', 'resource_class' => 'Foo', 'request_uri' => ''];
+ $this->assertEquals($expected, $this->builder->createFromRequest($request, true));
+
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get', '_api_format' => 'xml', '_api_mime_type' => 'text/xml']);
+ $expected = ['bar' => 'baz', 'item_operation_name' => 'get', 'resource_class' => 'Foo', 'request_uri' => ''];
+ $this->assertEquals($expected, $this->builder->createFromRequest($request, false));
+
+ $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'post', '_api_format' => 'xml', '_api_mime_type' => 'text/xml']);
+ $expected = ['bar' => 'baz', 'collection_operation_name' => 'post', 'resource_class' => 'Foo', 'request_uri' => ''];
+ $this->assertEquals($expected, $this->builder->createFromRequest($request, false));
+ }
+
+ /**
+ * @expectedException \ApiPlatform\Core\Exception\RuntimeException
+ */
+ public function testThrowExceptionOnInvalidRequest()
+ {
+ $this->builder->createFromRequest(new Request(), false);
+ }
+
+ public function testReuseExistingAttributes()
+ {
+ $expected = ['bar' => 'baz', 'item_operation_name' => 'get', 'resource_class' => 'Foo', 'request_uri' => ''];
+ $this->assertEquals($expected, $this->builder->createFromRequest(new Request(), false, ['resource_class' => 'Foo', 'item_operation_name' => 'get']));
+ }
+}