Skip to content

Commit 32cffa6

Browse files
committed
feat(mongodb): resource metadata collection
1 parent ce8366c commit 32cffa6

35 files changed

+226
-188
lines changed

src/Core/Bridge/Doctrine/EventListener/PublishMercureUpdatesListener.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,18 @@ public function __construct(ResourceClassResolverInterface $resourceClassResolve
9191
$this->graphQlMercureSubscriptionIriGenerator = $graphQlMercureSubscriptionIriGenerator;
9292
$this->reset();
9393

94-
$rawurlencode = ExpressionFunction::fromPhp('rawurlencode', 'escape');
95-
$this->expressionLanguage->addFunction($rawurlencode);
96-
97-
$this->expressionLanguage->addFunction(
98-
new ExpressionFunction('iri', static function (string $apiResource, int $referenceType = UrlGeneratorInterface::ABS_URL): string {
99-
return sprintf('iri(%s, %d)', $apiResource, $referenceType);
100-
}, static function (array $arguments, $apiResource, int $referenceType = UrlGeneratorInterface::ABS_URL) use ($iriConverter): string {
101-
return $iriConverter->getIriFromItem($apiResource, null, $referenceType);
102-
})
103-
);
94+
if ($this->expressionLanguage) {
95+
$rawurlencode = ExpressionFunction::fromPhp('rawurlencode', 'escape');
96+
$this->expressionLanguage->addFunction($rawurlencode);
97+
98+
$this->expressionLanguage->addFunction(
99+
new ExpressionFunction('iri', static function (string $apiResource, int $referenceType = UrlGeneratorInterface::ABS_URL): string {
100+
return sprintf('iri(%s, %d)', $apiResource, $referenceType);
101+
}, static function (array $arguments, $apiResource, int $referenceType = UrlGeneratorInterface::ABS_URL) use ($iriConverter): string {
102+
return $iriConverter->getIriFromItem($apiResource, null, $referenceType);
103+
})
104+
);
105+
}
104106
}
105107

106108
/**

src/Core/Bridge/Doctrine/MongoDbOdm/CollectionDataProvider.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
1919
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
2020
use ApiPlatform\Core\Exception\RuntimeException;
21-
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
22-
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
21+
use ApiPlatform\Exception\OperationNotFoundException;
2322
use Doctrine\ODM\MongoDB\DocumentManager;
2423
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
2524
use Doctrine\Persistence\ManagerRegistry;
@@ -43,11 +42,6 @@ final class CollectionDataProvider implements CollectionDataProviderInterface, R
4342
public function __construct(ManagerRegistry $managerRegistry, $resourceMetadataFactory, iterable $collectionExtensions = [])
4443
{
4544
$this->managerRegistry = $managerRegistry;
46-
47-
if (!$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
48-
trigger_deprecation('api-platform/core', '2.7', sprintf('Use "%s" instead of "%s".', ResourceMetadataCollectionFactoryInterface::class, ResourceMetadataFactoryInterface::class));
49-
}
50-
5145
$this->resourceMetadataFactory = $resourceMetadataFactory;
5246
$this->collectionExtensions = $collectionExtensions;
5347
}
@@ -81,7 +75,13 @@ public function getCollection(string $resourceClass, string $operationName = nul
8175
}
8276
}
8377

84-
$attribute = $this->resourceMetadataFactory->create($resourceClass)->getOperation($operationName)->getExtraProperties();
78+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
79+
try {
80+
$operation = $context['operation'] ?? (isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName));
81+
$attribute = $operation->getExtraProperties()['doctrine_mongodb'] ?? [];
82+
} catch (OperationNotFoundException $e) {
83+
$attribute = $resourceMetadata->getOperation(null, true)->getExtraProperties()['doctrine_mongodb'] ?? [];
84+
}
8585
$executeOptions = $attribute['execute_options'] ?? [];
8686

8787
return $aggregationBuilder->hydrate($resourceClass)->execute($executeOptions);

src/Core/Bridge/Doctrine/MongoDbOdm/Extension/FilterExtension.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Core\Api\FilterLocatorTrait;
1818
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface;
1919
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
20+
use ApiPlatform\Exception\OperationNotFoundException;
2021
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2122
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2223
use Psr\Container\ContainerInterface;
@@ -54,7 +55,13 @@ public function __construct($resourceMetadataFactory, $filterLocator)
5455
*/
5556
public function applyToCollection(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array &$context = [])
5657
{
57-
$resourceFilters = $this->resourceMetadataFactory->create($resourceClass)->getOperation($operationName)->getFilters();
58+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
59+
try {
60+
$operation = isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName);
61+
$resourceFilters = $operation->getFilters();
62+
} catch (OperationNotFoundException $e) {
63+
$resourceFilters = $resourceMetadata->getOperation(null, true)->getFilters();
64+
}
5865

5966
if (empty($resourceFilters)) {
6067
return;

src/Core/Bridge/Doctrine/MongoDbOdm/Extension/OrderExtension.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Core\Bridge\Doctrine\Common\PropertyHelperTrait;
1717
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\PropertyHelperTrait as MongoDbOdmPropertyHelperTrait;
1818
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
19+
use ApiPlatform\Exception\OperationNotFoundException;
1920
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2021
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2122
use Doctrine\Persistence\ManagerRegistry;
@@ -41,7 +42,7 @@ final class OrderExtension implements AggregationCollectionExtensionInterface
4142

4243
public function __construct(string $order = null, $resourceMetadataFactory = null, ManagerRegistry $managerRegistry = null)
4344
{
44-
if (!$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
45+
if ($resourceMetadataFactory && !$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
4546
trigger_deprecation('api-platform/core', '2.7', sprintf('Use "%s" instead of "%s".', ResourceMetadataCollectionFactoryInterface::class, ResourceMetadataFactoryInterface::class));
4647
}
4748

@@ -58,11 +59,22 @@ public function applyToCollection(Builder $aggregationBuilder, string $resourceC
5859
$classMetaData = $this->getClassMetadata($resourceClass);
5960
$identifiers = $classMetaData->getIdentifier();
6061
if (null !== $this->resourceMetadataFactory) {
61-
$defaultOrder = $this->resourceMetadataFactory->create($resourceClass)->getOperation($operationName)->getOrders();
62-
if (empty($defaultOrder)) {
62+
if ($this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
63+
if (isset($context['operation'])) {
64+
$defaultOrder = $context['operation']->getOrder();
65+
} else {
66+
$metadata = $this->resourceMetadataFactory->create($resourceClass);
67+
try {
68+
$defaultOrder = isset($context['graphql_operation_name']) ? $metadata->getGraphQlOperation($operationName)->getOrder() : $metadata->getOperation($operationName)->getOrder();
69+
} catch (OperationNotFoundException $e) {
70+
$defaultOrder = $metadata->getOperation(null, true)->getOrder();
71+
}
72+
}
73+
} else {
6374
$defaultOrder = $this->resourceMetadataFactory->create($resourceClass)->getAttribute('order');
6475
}
65-
if (null !== $defaultOrder) {
76+
77+
if ($defaultOrder) {
6678
foreach ($defaultOrder as $field => $order) {
6779
if (\is_int($field)) {
6880
// Default direction

src/Core/Bridge/Doctrine/MongoDbOdm/Extension/PaginationExtension.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Core\DataProvider\Pagination;
1818
use ApiPlatform\Core\Exception\RuntimeException;
1919
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
20+
use ApiPlatform\Exception\OperationNotFoundException;
2021
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2122
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2223
use Doctrine\ODM\MongoDB\DocumentManager;
@@ -122,7 +123,13 @@ public function getResult(Builder $aggregationBuilder, string $resourceClass, st
122123
throw new RuntimeException(sprintf('The manager for "%s" must be an instance of "%s".', $resourceClass, DocumentManager::class));
123124
}
124125

125-
$attribute = $this->resourceMetadataFactory->create($resourceClass)->getOperation($operationName)->getExtraProperties();
126+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
127+
try {
128+
$operation = $context['operation'] ?? (isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName));
129+
$attribute = $operation->getExtraProperties()['doctrine_mongodb'] ?? [];
130+
} catch (OperationNotFoundException $e) {
131+
$attribute = $resourceMetadata->getOperation(null, true)->getExtraProperties()['doctrine_mongodb'] ?? [];
132+
}
126133
$executeOptions = $attribute['execute_options'] ?? [];
127134

128135
return new Paginator($aggregationBuilder->execute($executeOptions), $manager->getUnitOfWork(), $resourceClass, $aggregationBuilder->getPipeline());

src/Core/Bridge/Doctrine/MongoDbOdm/ItemDataProvider.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2525
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
2626
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
27+
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
2728
use Doctrine\ODM\MongoDB\DocumentManager;
2829
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
2930
use Doctrine\Persistence\ManagerRegistry;
@@ -105,7 +106,13 @@ public function getItem(string $resourceClass, $id, string $operationName = null
105106
}
106107

107108
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
108-
$attribute = $resourceMetadata->getItemOperationAttribute($operationName, 'doctrine_mongodb', [], true);
109+
110+
if ($resourceMetadata instanceof ResourceMetadataCollection) {
111+
$attribute = $resourceMetadata->getOperation($operationName)->getExtraProperties()['doctrine_mongodb'] ?? [];
112+
} else {
113+
$attribute = $resourceMetadata->getItemOperationAttribute($operationName, 'doctrine_mongodb', [], true);
114+
}
115+
109116
$executeOptions = $attribute['execute_options'] ?? [];
110117

111118
return $aggregationBuilder->hydrate($resourceClass)->execute($executeOptions)->current() ?: null;

src/Core/Bridge/Doctrine/MongoDbOdm/PropertyInfo/DoctrineExtractor.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ public function getTypes($class, $property, array $context = [])
6363
}
6464

6565
if ($metadata->hasAssociation($property)) {
66+
/** @var class-string|null */
6667
$class = $metadata->getAssociationTargetClass($property);
6768

69+
if (null === $class) {
70+
return null;
71+
}
72+
6873
if ($metadata->isSingleValuedAssociation($property)) {
6974
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
7075

src/Core/Bridge/Doctrine/MongoDbOdm/SubresourceDataProvider.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2626
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2727
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
28+
use ApiPlatform\Exception\OperationNotFoundException;
2829
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2930
use Doctrine\ODM\MongoDB\Aggregation\Builder;
3031
use Doctrine\ODM\MongoDB\DocumentManager;
@@ -85,11 +86,23 @@ public function getSubresource(string $resourceClass, array $identifiers, array
8586
throw new RuntimeException(sprintf('The repository for "%s" must be an instance of "%s".', $resourceClass, DocumentRepository::class));
8687
}
8788

89+
if (isset($context['identifiers'], $context['operation']) && !isset($context['property'])) {
90+
$context['property'] = $context['operation']->getExtraProperties()['legacy_subresource_property'] ?? null;
91+
$context['collection'] = $context['operation']->isCollection();
92+
}
93+
8894
if (!isset($context['identifiers'], $context['property'])) {
8995
throw new ResourceClassNotSupportedException('The given resource class is not a subresource.');
9096
}
9197

92-
$attribute = $this->resourceMetadataFactory->create($resourceClass)->getOperation($operationName)->getExtraProperties();
98+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
99+
try {
100+
$operation = $context['operation'] ?? (isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName));
101+
$attribute = $operation->getExtraProperties()['doctrine_mongodb'] ?? [];
102+
} catch (OperationNotFoundException $e) {
103+
$attribute = $resourceMetadata->getOperation()->getExtraProperties()['doctrine_mongodb'] ?? [];
104+
}
105+
93106
$executeOptions = $attribute['execute_options'] ?? [];
94107

95108
$aggregationBuilder = $this->buildAggregation($identifiers, $context, $executeOptions, $repository->createAggregationBuilder(), \count($context['identifiers']));

src/Core/Bridge/Doctrine/Orm/Extension/FilterExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
6969
$resourceFilters = $resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true);
7070
} else {
7171
try {
72-
$operation = isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName);
72+
$operation = $context['operation'] ?? (isset($context['graphql_operation_name']) ? $resourceMetadata->getGraphQlOperation($operationName) : $resourceMetadata->getOperation($operationName));
7373
$resourceFilters = $operation->getFilters();
7474
} catch (OperationNotFoundException $e) {
7575
// In some cases the operation may not exist

src/Core/Bridge/Symfony/Bundle/Resources/config/api.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@
133133
<tag name="serializer.normalizer" priority="-895" />
134134
</service>
135135

136+
<service id="api_platform.serializer.mapping.class_metadata_factory" class="ApiPlatform\Core\Serializer\Mapping\Factory\ClassMetadataFactory" decorates="serializer.mapping.class_metadata_factory" decoration-priority="-1" public="false">
137+
<argument type="service" id="api_platform.serializer.mapping.class_metadata_factory.inner" />
138+
</service>
139+
136140
<!-- Resources Operations path resolver -->
137141

138142
<service id="api_platform.operation_path_resolver" alias="api_platform.operation_path_resolver.router" public="false" />

0 commit comments

Comments
 (0)