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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Action/ActionUtilTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ApiPlatform\Core\Action;

use ApiPlatform\Core\Api\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Expand Down
4 changes: 2 additions & 2 deletions src/Action/GetCollectionAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

namespace ApiPlatform\Core\Action;

use ApiPlatform\Core\Api\CollectionDataProviderInterface;
use ApiPlatform\Core\Api\PaginatorInterface;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\PaginatorInterface;
use ApiPlatform\Core\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;

Expand Down
2 changes: 1 addition & 1 deletion src/Action/GetItemAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ApiPlatform\Core\Action;

use ApiPlatform\Core\Api\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Expand Down
2 changes: 1 addition & 1 deletion src/Action/PutItemAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ApiPlatform\Core\Action;

use ApiPlatform\Core\Api\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Expand Down
1 change: 1 addition & 0 deletions src/Api/ResourceClassResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace ApiPlatform\Core\Api;

use ApiPlatform\Core\DataProvider\PaginatorInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
use ApiPlatform\Core\Util\ClassInfoTrait;
Expand Down
19 changes: 4 additions & 15 deletions src/Bridge/Doctrine/Orm/CollectionDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

namespace ApiPlatform\Core\Bridge\Doctrine\Orm;

use ApiPlatform\Core\Api\CollectionDataProviderInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultExtensionInterface;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use Doctrine\Common\Persistence\ManagerRegistry;

Expand All @@ -27,33 +27,22 @@ class CollectionDataProvider implements CollectionDataProviderInterface
{
private $managerRegistry;
private $collectionExtensions;
private $decorated;

/**
* @param ManagerRegistry $managerRegistry
* @param QueryCollectionExtensionInterface[] $collectionExtensions
* @param CollectionDataProviderInterface|null $decorated
* @param ManagerRegistry $managerRegistry
* @param QueryCollectionExtensionInterface[] $collectionExtensions
*/
public function __construct(ManagerRegistry $managerRegistry, array $collectionExtensions = [], CollectionDataProviderInterface $decorated = null)
public function __construct(ManagerRegistry $managerRegistry, array $collectionExtensions = [])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dunglas this one could be final as well

{
$this->managerRegistry = $managerRegistry;
$this->collectionExtensions = $collectionExtensions;
$this->decorated = $decorated;
}

/**
* {@inheritdoc}
*/
public function getCollection(string $resourceClass, string $operationName = null)
{
if ($this->decorated) {
try {
return $this->decorated->getCollection($resourceClass, $operationName);
} catch (ResourceClassNotSupportedException $resourceClassNotSupportedException) {
// Ignore it
}
}

$manager = $this->managerRegistry->getManagerForClass($resourceClass);
if (null === $manager) {
throw new ResourceClassNotSupportedException();
Expand Down
15 changes: 2 additions & 13 deletions src/Bridge/Doctrine/Orm/ItemDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

namespace ApiPlatform\Core\Bridge\Doctrine\Orm;

use ApiPlatform\Core\Api\ItemDataProviderInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
Expand All @@ -33,37 +33,26 @@ class ItemDataProvider implements ItemDataProviderInterface
private $propertyNameCollectionFactory;
private $propertyMetadataFactory;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

private $itemExtensions;
private $decorated;

/**
* @param ManagerRegistry $managerRegistry
* @param PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory
* @param PropertyMetadataFactoryInterface $propertyMetadataFactory
* @param QueryItemExtensionInterface[] $itemExtensions
* @param ItemDataProviderInterface|null $decorated
*/
public function __construct(ManagerRegistry $managerRegistry, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, array $itemExtensions = [], ItemDataProviderInterface $decorated = null)
public function __construct(ManagerRegistry $managerRegistry, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, array $itemExtensions = [])
{
$this->managerRegistry = $managerRegistry;
$this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
$this->propertyMetadataFactory = $propertyMetadataFactory;
$this->itemExtensions = $itemExtensions;
$this->decorated = $decorated;
}

/**
* {@inheritdoc}
*/
public function getItem(string $resourceClass, $id, string $operationName = null, bool $fetchData = false)
{
if ($this->decorated) {
try {
return $this->decorated->getItem($resourceClass, $id, $operationName, $fetchData);
} catch (ResourceClassNotSupportedException $resourceClassNotSupportedException) {
// Ignore it
}
}

$manager = $this->managerRegistry->getManagerForClass($resourceClass);
if (null === $manager) {
throw new ResourceClassNotSupportedException();
Expand Down
2 changes: 1 addition & 1 deletion src/Bridge/Doctrine/Orm/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ApiPlatform\Core\Bridge\Doctrine\Orm;

use ApiPlatform\Core\Api\PaginatorInterface;
use ApiPlatform\Core\DataProvider\PaginatorInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator;

Expand Down
2 changes: 2 additions & 0 deletions src/Bridge/Symfony/Bundle/ApiPlatformBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace ApiPlatform\Core\Bridge\Symfony\Bundle;

use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\DataProviderPass;
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\DoctrineQueryExtensionPass;
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\FilterPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand All @@ -30,6 +31,7 @@ public function build(ContainerBuilder $container)
{
parent::build($container);

$container->addCompilerPass(new DataProviderPass());
$container->addCompilerPass(new FilterPass());
$container->addCompilerPass(new DoctrineQueryExtensionPass());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('api.xml');
$loader->load('metadata.xml');
$loader->load('data_provider.xml');

$this->enableJsonLd($loader);
$this->registerAnnotationLoaders($container);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?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.
*/

namespace ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Registers data providers.
*
* @internal
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
final class DataProviderPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$this->registerDataProviders($container, 'collection');
$this->registerDataProviders($container, 'item');
}

/**
* The priority sorting algorithm has been backported from Symfony 3.2.
*
* @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php
*
* @param ContainerBuilder $container
* @param string $type
*/
private function registerDataProviders(ContainerBuilder $container, string $type)
{
$services = $container->findTaggedServiceIds('api_platform.'.$type.'_data_provider');

$queue = new \SplPriorityQueue();

foreach ($services as $serviceId => $tags) {
foreach ($tags as $attributes) {
$priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
$queue->insert(new Reference($serviceId), $priority);
}
}

$container->getDefinition('api_platform.'.$type.'_data_provider')->addArgument(iterator_to_array($queue, false));
}
}
2 changes: 0 additions & 2 deletions src/Bridge/Symfony/Bundle/Resources/config/api.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

<service id="api_platform.property_info" alias="property_info" public="false" />

<service id="api_platform.filters" class="ApiPlatform\Core\Api\FilterCollection" public="false" />

<service id="api_platform.resource_class_resolver" class="ApiPlatform\Core\Api\ResourceClassResolver" public="false">
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
</service>
Expand Down
15 changes: 15 additions & 0 deletions src/Bridge/Symfony/Bundle/Resources/config/data_provider.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="api_platform.item_data_provider" class="ApiPlatform\Core\DataProvider\ChainItemDataProvider" />

<service id="api_platform.collection_data_provider" class="ApiPlatform\Core\DataProvider\ChainCollectionDataProvider" />

<service id="api_platform.filters" class="ApiPlatform\Core\Api\FilterCollection" public="false" />
</services>

</container>
12 changes: 7 additions & 5 deletions src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="api_platform.item_data_provider" alias="api_platform.doctrine.orm.default.item_data_provider" />
<service id="api_platform.collection_data_provider" alias="api_platform.doctrine.orm.default.collection_data_provider" />

<service id="api_platform.doctrine.metadata_factory" class="Doctrine\Common\Persistence\Mapping\ClassMetadataFactory" public="false">
<factory service="doctrine.orm.default_entity_manager" method="getMetadataFactory" />
</service>
Expand All @@ -24,8 +21,13 @@
<argument type="collection"></argument> <!-- extensions -->
</service>

<service id="api_platform.doctrine.orm.default.collection_data_provider" parent="api_platform.doctrine.orm.collection_data_provider" class="ApiPlatform\Core\Bridge\Doctrine\Orm\CollectionDataProvider" />
<service id="api_platform.doctrine.orm.default.item_data_provider" parent="api_platform.doctrine.orm.item_data_provider" class="ApiPlatform\Core\Bridge\Doctrine\Orm\ItemDataProvider" />
<service id="api_platform.doctrine.orm.default.collection_data_provider" parent="api_platform.doctrine.orm.collection_data_provider" class="ApiPlatform\Core\Bridge\Doctrine\Orm\CollectionDataProvider">
<tag name="api_platform.collection_data_provider" />
</service>

<service id="api_platform.doctrine.orm.default.item_data_provider" parent="api_platform.doctrine.orm.item_data_provider" class="ApiPlatform\Core\Bridge\Doctrine\Orm\ItemDataProvider">
<tag name="api_platform.item_data_provider" />
</service>

<!-- Filter -->

Expand Down
2 changes: 1 addition & 1 deletion src/Bridge/Symfony/Routing/IriConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
namespace ApiPlatform\Core\Bridge\Symfony\Routing;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ItemDataProviderInterface;
use ApiPlatform\Core\Api\UrlGeneratorInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
Expand Down
46 changes: 46 additions & 0 deletions src/DataProvider/ChainCollectionDataProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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.
*/

namespace ApiPlatform\Core\DataProvider;

use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;

/**
* Tries each configured data provider and returns the result of the first able to handle the resource class.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
final class ChainCollectionDataProvider implements CollectionDataProviderInterface
{
private $dataProviders;

/**
* @param CollectionDataProviderInterface[] $dataProviders
*/
public function __construct(array $dataProviders)
{
$this->dataProviders = $dataProviders;
}

/**
* {@inheritdoc}
*/
public function getCollection(string $resourceClass, string $operationName = null)
{
foreach ($this->dataProviders as $dataProvider) {
try {
return $dataProvider->getCollection($resourceClass, $operationName);
} catch (ResourceClassNotSupportedException $e) {
continue;
}
}
}
}
46 changes: 46 additions & 0 deletions src/DataProvider/ChainItemDataProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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.
*/

namespace ApiPlatform\Core\DataProvider;

use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;

/**
* Tries each configured data provider and returns the result of the first able to handle the resource class.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
final class ChainItemDataProvider implements ItemDataProviderInterface
{
private $dataProviders;

/**
* @param ItemDataProviderInterface[] $dataProviders
*/
public function __construct(array $dataProviders)
{
$this->dataProviders = $dataProviders;
}

/**
* {@inheritdoc}
*/
public function getItem(string $resourceClass, $id, string $operationName = null, bool $fetchData = false)
{
foreach ($this->dataProviders as $dataProviders) {
try {
return $dataProviders->getItem($resourceClass, $id, $operationName, $fetchData);
} catch (ResourceClassNotSupportedException $e) {
continue;
}
}
}
}
Loading