Skip to content

Commit

Permalink
Merge 602120b into d805e9a
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Apr 20, 2018
2 parents d805e9a + 602120b commit f4abdb1
Show file tree
Hide file tree
Showing 10 changed files with 309 additions and 413 deletions.
2 changes: 1 addition & 1 deletion src/Bridge/Symfony/Bundle/Resources/config/api.xml
Expand Up @@ -58,7 +58,7 @@
<argument type="service" id="api_platform.router" />
<argument type="service" id="api_platform.property_accessor" />
<argument type="service" id="api_platform.identifiers_extractor.cached" />
<argument type="service" id="api_platform.identifier.denormalizer" />
<argument type="service" id="api_platform.operation_data_provider" />
</service>
<service id="ApiPlatform\Core\Api\IriConverterInterface" alias="api_platform.iri_converter" />

Expand Down
7 changes: 7 additions & 0 deletions src/Bridge/Symfony/Bundle/Resources/config/data_provider.xml
Expand Up @@ -26,6 +26,13 @@
<argument type="tagged" tag="api_platform.subresource_data_provider" />
</service>
<service id="ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface" alias="api_platform.subresource_data_provider" />

<service id="api_platform.operation_data_provider" class="ApiPlatform\Core\DataProvider\OperationDataProvider">
<argument type="service" id="api_platform.collection_data_provider" />
<argument type="service" id="api_platform.item_data_provider" />
<argument type="service" id="api_platform.subresource_data_provider" />
<argument type="service" id="api_platform.identifier.denormalizer" />
</service>
</services>

</container>
37 changes: 21 additions & 16 deletions src/Bridge/Symfony/Routing/IriConverter.php
Expand Up @@ -19,10 +19,10 @@
use ApiPlatform\Core\Api\OperationType;
use ApiPlatform\Core\Api\UrlGeneratorInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\OperationDataProvider;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Exception\RuntimeException;
use ApiPlatform\Core\Identifier\Normalizer\ChainIdentifierDenormalizer;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Core\Util\ClassInfoTrait;
Expand All @@ -44,24 +44,27 @@ final class IriConverter implements IriConverterInterface
private $routeNameResolver;
private $router;
private $identifiersExtractor;
private $identifierDenormalizer;
private $operationDataProvider;

public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null, ChainIdentifierDenormalizer $identifierDenormalizer = null)
/**
* Arguments should be RouteNameResolverInterface, RouterInterface, PropertyAccessorInterface, IdentifiersExtractorInterface, OperationDataProvider
* The rest is not used anymore.
*/
public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null, OperationDataProvider $operationDataProvider = null)
{
$this->itemDataProvider = $itemDataProvider;
$this->routeNameResolver = $routeNameResolver;
$this->router = $router;
$this->identifierDenormalizer = $identifierDenormalizer;
$this->identifiersExtractor = $identifiersExtractor;
$this->operationDataProvider = $operationDataProvider;

if (null === $identifiersExtractor) {
@trigger_error('Not injecting ItemIdentifiersExtractor is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3', E_USER_DEPRECATED);
$this->identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, $propertyAccessor ?? PropertyAccess::createPropertyAccessor());
} else {
$this->identifiersExtractor = $identifiersExtractor;
}

if (null === $identifierDenormalizer) {
@trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.2 and will not be possible anymore in API Platform 3.', ChainIdentifierDenormalizer::class), E_USER_DEPRECATED);
if (null === $operationDataProvider) {
@trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.2 and will not be possible anymore in API Platform 3.', OperationDataProvider::class), E_USER_DEPRECATED);
}
}

Expand All @@ -76,18 +79,20 @@ public function getItemFromIri(string $iri, array $context = [])
throw new InvalidArgumentException(sprintf('No route matches "%s".', $iri), $e->getCode(), $e);
}

if (!isset($parameters['_api_resource_class'], $parameters['id'])) {
throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
}
if ($this->operationDataProvider) {
if ($item = $this->operationDataProvider->getDataFromRouteParameters($iri, $parameters, $context)) {
return $item;
}

$identifiers = $parameters['id'];
throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
}

if ($this->identifierDenormalizer) {
$identifiers = $this->identifierDenormalizer->denormalize((string) $parameters['id'], $parameters['_api_resource_class']);
$context[ChainIdentifierDenormalizer::HAS_IDENTIFIER_DENORMALIZER] = true;
// Legacy code below
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['_api_resource_class'], $identifiers, $parameters['_api_item_operation_name'] ?? null, $context)) {
if ($item = $this->itemDataProvider->getItem($parameters['_api_resource_class'], $parameters['id'], $parameters['_api_item_operation_name'] ?? null, $context)) {
return $item;
}

Expand Down
51 changes: 51 additions & 0 deletions src/DataProvider/OperationDataProvider.php
@@ -0,0 +1,51 @@
<?php

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

declare(strict_types=1);

namespace ApiPlatform\Core\DataProvider;

use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Identifier\Normalizer\ChainIdentifierDenormalizer;
use ApiPlatform\Core\Util\RequestAttributesExtractor;

/**
* @internal
*/
class OperationDataProvider
{
use OperationDataProviderTrait;

public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider, ChainIdentifierDenormalizer $identifierDenormalizer)
{
$this->collectionDataProvider = $collectionDataProvider;
$this->itemDataProvider = $itemDataProvider;
$this->subresourceDataProvider = $subresourceDataProvider;
$this->identifierDenormalizer = $identifierDenormalizer;
}

public function getDataFromRouteParameters(string $iri = null, array $parameters, array $context = [])
{
if (!isset($parameters['_api_resource_class'])) {
throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
}

$attributes = RequestAttributesExtractor::extractAttributesFromParameters($parameters);
$identifiers = $this->extractIdentifiers($parameters, $attributes);
$context[ChainIdentifierDenormalizer::HAS_IDENTIFIER_DENORMALIZER] = true;

if (isset($attributes['subresource_operation_name'])) {
return $this->getSubresourceData($identifiers, $attributes, $context);
}

return $this->getItemData($identifiers, $attributes, $context);
}
}
106 changes: 106 additions & 0 deletions src/DataProvider/OperationDataProviderTrait.php
@@ -0,0 +1,106 @@
<?php

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

declare(strict_types=1);

namespace ApiPlatform\Core\DataProvider;

use ApiPlatform\Core\Exception\InvalidIdentifierException;
use ApiPlatform\Core\Identifier\Normalizer\ChainIdentifierDenormalizer;

trait OperationDataProviderTrait
{
/**
* @var CollectionDataProviderInterface
*/
private $collectionDataProvider;
/**
* @var ItemDataProviderInterface
*/
private $itemDataProvider;
/**
* @var SubresourceDataProviderInterface
*/
private $subresourceDataProvider;
/**
* @var ChainIdentifierDenormalizer
*/
private $identifierDenormalizer;

/**
* Retrieves data for a collection operation.
*
* @return array|\Traversable|null
*/
private function getCollectionData(array $attributes, array $context)
{
return $this->collectionDataProvider->getCollection($attributes['resource_class'], $attributes['collection_operation_name'], $context);
}

/**
* Gets data for an item operation.
*
* @throws NotFoundHttpException
*
* @return object|null
*/
private function getItemData($identifiers, array $attributes, array $context)
{
return $this->itemDataProvider->getItem($attributes['resource_class'], $identifiers, $attributes['item_operation_name'], $context);
}

/**
* Gets data for a nested operation.
*
* @throws NotFoundHttpException
* @throws RuntimeException
*
* @return object|null
*/
private function getSubresourceData($identifiers, array $attributes, array $context)
{
return $this->subresourceDataProvider->getSubresource($attributes['resource_class'], $identifiers, $attributes['subresource_context'] + $context, $attributes['subresource_operation_name']);
}

/**
* @param array $parameters - usually comes from $request->attributes->all()
*
* @throws InvalidIdentifierException
*/
private function extractIdentifiers(array $parameters, array $attributes)
{
if (isset($attributes['item_operation_name'])) {
$id = $parameters['id'];

if ($this->identifierDenormalizer) {
return $this->identifierDenormalizer->denormalize((string) $id, $attributes['resource_class']);
}

return $id;
}

$identifiers = [];

foreach ($attributes['subresource_context']['identifiers'] as $key => list($id, $resourceClass, $hasIdentifier)) {
if (false === $hasIdentifier) {
continue;
}

$identifiers[$id] = $parameters[$id];

if ($this->identifierDenormalizer) {
$identifiers[$id] = $this->identifierDenormalizer->denormalize((string) $identifiers[$id], $resourceClass);
}
}

return $identifiers;
}
}

0 comments on commit f4abdb1

Please sign in to comment.