Skip to content

Commit 7f29458

Browse files
committed
fix(state): operation argument in provide/process
1 parent 17df55a commit 7f29458

File tree

99 files changed

+2217
-2402
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2217
-2402
lines changed

src/Core/EventListener/ReadListener.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ public function onKernelRequest(RequestEvent $event): void
7575
if (
7676
!($attributes = RequestAttributesExtractor::extractAttributes($request))
7777
|| !$attributes['receive']
78-
|| $request->isMethod('POST') && isset($attributes['collection_operation_name'])
78+
|| ($request->isMethod('POST') && isset($attributes['collection_operation_name']))
7979
|| ($operation && !($operation->getExtraProperties()['is_legacy_resource_metadata'] ?? false) && !($operation->getExtraProperties()['is_legacy_subresource'] ?? false))
80+
|| ($operation && false === $operation->canRead())
8081
|| $this->isOperationAttributeDisabled($attributes, self::OPERATION_ATTRIBUTE_KEY)
8182
) {
8283
return;

src/Core/Metadata/Resource/ApiResourceToLegacyResourceMetadataTrait.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Core\Metadata\Resource;
1515

1616
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\CollectionOperationInterface;
1718
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
1819

1920
/**
@@ -39,10 +40,11 @@ private function transformResourceToResourceMetadata(ApiResource $resource): Res
3940
$arrayOperation['openapi_context']['operationId'] = $name;
4041

4142
if ($operation->getExtraProperties()['is_alternate_resource_metadata'] ?? false) {
42-
$arrayOperation['composite_identifier'] = $operation->getCompositeIdentifier() ?? false;
43+
// TODO ?
44+
// $arrayOperation['composite_identifier'] = $operation->getCompositeIdentifier() ?? false;
4345
}
4446

45-
if ($operation->isCollection()) {
47+
if ($operation instanceof CollectionOperationInterface) {
4648
$collectionOperations[$name] = $arrayOperation;
4749
continue;
4850
}

src/Doctrine/Common/State/LinksHandlerTrait.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Doctrine\Common\State;
1515

1616
use ApiPlatform\Exception\RuntimeException;
17+
use ApiPlatform\Metadata\AbstractOperation;
1718
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
1819
use ApiPlatform\Metadata\Link;
1920
use ApiPlatform\Metadata\Operation;
@@ -25,7 +26,7 @@ trait LinksHandlerTrait
2526
*
2627
* @return Link[]
2728
*/
28-
private function getLinks(string $resourceClass, $operation, array $context): array
29+
private function getLinks(string $resourceClass, AbstractOperation $operation, array $context): array
2930
{
3031
$links = ($operation instanceof GraphQlOperation ? $operation->getLinks() : $operation->getUriVariables()) ?? [];
3132

src/Doctrine/Common/State/Processor.php renamed to src/Doctrine/Common/State/PersistProcessor.php

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313

1414
namespace ApiPlatform\Doctrine\Common\State;
1515

16+
use ApiPlatform\Metadata\AbstractOperation;
1617
use ApiPlatform\State\ProcessorInterface;
1718
use ApiPlatform\Util\ClassInfoTrait;
1819
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
1920
use Doctrine\ORM\Mapping\ClassMetadataInfo;
2021
use Doctrine\Persistence\ManagerRegistry;
2122
use Doctrine\Persistence\ObjectManager as DoctrineObjectManager;
2223

23-
final class Processor implements ProcessorInterface
24+
final class PersistProcessor implements ProcessorInterface
2425
{
2526
use ClassInfoTrait;
2627

@@ -31,12 +32,7 @@ public function __construct(ManagerRegistry $managerRegistry)
3132
$this->managerRegistry = $managerRegistry;
3233
}
3334

34-
public function supports($data, array $uriVariables = [], ?string $operationName = null, array $context = []): bool
35-
{
36-
return null !== $this->getManager($data);
37-
}
38-
39-
private function persist($data, array $context = [])
35+
public function process($data, AbstractOperation $operation, array $uriVariables = [], array $context = [])
4036
{
4137
if (!$manager = $this->getManager($data)) {
4238
return $data;
@@ -52,25 +48,6 @@ private function persist($data, array $context = [])
5248
return $data;
5349
}
5450

55-
private function remove($data, array $context = [])
56-
{
57-
if (!$manager = $this->getManager($data)) {
58-
return;
59-
}
60-
61-
$manager->remove($data);
62-
$manager->flush();
63-
}
64-
65-
public function process($data, array $uriVariables = [], ?string $operationName = null, array $context = [])
66-
{
67-
if (\array_key_exists('operation', $context) && $context['operation']->isDelete()) {
68-
return $this->remove($data);
69-
}
70-
71-
return $this->persist($data);
72-
}
73-
7451
/**
7552
* Gets the Doctrine object manager associated with given data.
7653
*
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Doctrine\Common\State;
15+
16+
use ApiPlatform\Metadata\AbstractOperation;
17+
use ApiPlatform\State\ProcessorInterface;
18+
use ApiPlatform\Util\ClassInfoTrait;
19+
use Doctrine\Persistence\ManagerRegistry;
20+
use Doctrine\Persistence\ObjectManager as DoctrineObjectManager;
21+
22+
final class RemoveProcessor implements ProcessorInterface
23+
{
24+
use ClassInfoTrait;
25+
26+
private $managerRegistry;
27+
28+
public function __construct(ManagerRegistry $managerRegistry)
29+
{
30+
$this->managerRegistry = $managerRegistry;
31+
}
32+
33+
public function process($data, AbstractOperation $operation, array $uriVariables = [], array $context = [])
34+
{
35+
if (!$manager = $this->getManager($data)) {
36+
return;
37+
}
38+
39+
$manager->remove($data);
40+
$manager->flush();
41+
}
42+
43+
/**
44+
* Gets the Doctrine object manager associated with given data.
45+
*
46+
* @param mixed $data
47+
*/
48+
private function getManager($data): ?DoctrineObjectManager
49+
{
50+
return \is_object($data) ? $this->managerRegistry->getManagerForClass($this->getObjectClass($data)) : null;
51+
}
52+
}

src/Doctrine/Odm/State/CollectionProvider.php

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface;
1818
use ApiPlatform\Exception\OperationNotFoundException;
1919
use ApiPlatform\Exception\RuntimeException;
20-
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
20+
use ApiPlatform\Metadata\AbstractOperation;
2121
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2222
use ApiPlatform\State\ProviderInterface;
2323
use Doctrine\ODM\MongoDB\DocumentManager;
@@ -46,8 +46,9 @@ public function __construct(ResourceMetadataCollectionFactoryInterface $resource
4646
$this->collectionExtensions = $collectionExtensions;
4747
}
4848

49-
public function provide(string $resourceClass, array $uriVariables = [], ?string $operationName = null, array $context = [])
49+
public function provide(AbstractOperation $operation, array $uriVariables = [], array $context = [])
5050
{
51+
$resourceClass = $operation->getClass();
5152
/** @var DocumentManager $manager */
5253
$manager = $this->managerRegistry->getManagerForClass($resourceClass);
5354

@@ -80,19 +81,4 @@ public function provide(string $resourceClass, array $uriVariables = [], ?string
8081

8182
return $aggregationBuilder->hydrate($resourceClass)->execute($executeOptions);
8283
}
83-
84-
public function supports(string $resourceClass, array $uriVariables = [], ?string $operationName = null, array $context = []): bool
85-
{
86-
if (!$this->managerRegistry->getManagerForClass($resourceClass) instanceof DocumentManager) {
87-
return false;
88-
}
89-
90-
$operation = $context['operation'] ?? $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($operationName);
91-
92-
if ($operation instanceof GraphQlOperation) {
93-
return true;
94-
}
95-
96-
return $operation->isCollection() ?? false;
97-
}
9884
}

src/Doctrine/Odm/State/ItemProvider.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface;
1717
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultItemExtensionInterface;
1818
use ApiPlatform\Exception\RuntimeException;
19+
use ApiPlatform\Metadata\AbstractOperation;
1920
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2021
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
2122
use ApiPlatform\State\ProviderInterface;
@@ -48,8 +49,9 @@ public function __construct(ResourceMetadataCollectionFactoryInterface $resource
4849
$this->itemExtensions = $itemExtensions;
4950
}
5051

51-
public function provide(string $resourceClass, array $uriVariables = [], ?string $operationName = null, array $context = [])
52+
public function provide(AbstractOperation $operation, array $uriVariables = [], array $context = [])
5253
{
54+
$resourceClass = $operation->getClass();
5355
/** @var DocumentManager $manager */
5456
$manager = $this->managerRegistry->getManagerForClass($resourceClass);
5557

@@ -86,15 +88,4 @@ public function provide(string $resourceClass, array $uriVariables = [], ?string
8688

8789
return $aggregationBuilder->hydrate($resourceClass)->execute($executeOptions)->current() ?: null;
8890
}
89-
90-
public function supports(string $resourceClass, array $uriVariables = [], ?string $operationName = null, array $context = []): bool
91-
{
92-
if (!$this->managerRegistry->getManagerForClass($resourceClass) instanceof DocumentManager) {
93-
return false;
94-
}
95-
96-
$operation = $context['operation'] ?? $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($operationName);
97-
98-
return !($operation->isCollection() ?? false);
99-
}
10091
}

src/Doctrine/Orm/Extension/OrderExtension.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
8080
$defaultOrder = $this->resourceMetadataFactory->create($resourceClass)->getCollectionOperationAttribute($operationName, 'order', [], true);
8181
}
8282

83-
// TODO: 3.0 default value is [] not null
8483
if (null !== $defaultOrder && [] !== $defaultOrder) {
8584
foreach ($defaultOrder as $field => $order) {
8685
if (\is_int($field)) {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Doctrine\Orm\Metadata\Resource;
15+
16+
use ApiPlatform\Doctrine\Common\State\PersistProcessor;
17+
use ApiPlatform\Doctrine\Common\State\RemoveProcessor;
18+
use ApiPlatform\Doctrine\Orm\State\CollectionProvider;
19+
use ApiPlatform\Doctrine\Orm\State\ItemProvider;
20+
use ApiPlatform\Metadata\AbstractOperation;
21+
use ApiPlatform\Metadata\CollectionOperationInterface;
22+
use ApiPlatform\Metadata\DeleteOperationInterface;
23+
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
24+
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
25+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\AttributeResource;
26+
use Doctrine\ORM\EntityManagerInterface;
27+
use Doctrine\Persistence\ManagerRegistry;
28+
29+
class DoctrineOrmResourceCollectionMetadataFactory implements ResourceMetadataCollectionFactoryInterface
30+
{
31+
/**
32+
* @var ManagerRegistry
33+
*/
34+
private $managerRegistry;
35+
36+
/**
37+
* @var ResourceMetadataCollectionFactoryInterface
38+
*/
39+
private $decorated;
40+
41+
public function __construct(ManagerRegistry $managerRegistry, ResourceMetadataCollectionFactoryInterface $decorated)
42+
{
43+
$this->decorated = $decorated;
44+
$this->managerRegistry = $managerRegistry;
45+
}
46+
47+
/**
48+
* {@inheritDoc}
49+
*/
50+
public function create(string $resourceClass): ResourceMetadataCollection
51+
{
52+
$resourceMetadataCollection = $this->decorated->create($resourceClass);
53+
54+
foreach ($resourceMetadataCollection as $i => $resourceMetadata) {
55+
$operations = $resourceMetadata->getOperations();
56+
57+
if ($operations) {
58+
foreach ($resourceMetadata->getOperations() as $operationName => $operation) {
59+
if (!$this->managerRegistry->getManagerForClass($operation->getClass()) instanceof EntityManagerInterface) {
60+
continue;
61+
}
62+
63+
$operations->add($operationName, $this->addDefaults($operation));
64+
}
65+
66+
$resourceMetadata = $resourceMetadata->withOperations($operations);
67+
}
68+
69+
$graphQlOperations = $resourceMetadata->getGraphQlOperations();
70+
71+
if ($graphQlOperations) {
72+
foreach ($graphQlOperations as $operationName => $graphQlOperation) {
73+
if (!$this->managerRegistry->getManagerForClass($graphQlOperation->getClass()) instanceof EntityManagerInterface) {
74+
continue;
75+
}
76+
77+
$graphQlOperations[$operationName] = $this->addDefaults($graphQlOperation);
78+
}
79+
80+
$resourceMetadata = $resourceMetadata->withGraphQlOperations($graphQlOperations);
81+
}
82+
83+
$resourceMetadataCollection[$i] = $resourceMetadata;
84+
}
85+
86+
return $resourceMetadataCollection;
87+
}
88+
89+
private function addDefaults($operation): AbstractOperation
90+
{
91+
if (null === $operation->getProvider()) {
92+
$operation = $operation->withProvider($this->getProvider($operation));
93+
}
94+
95+
if (null === $operation->getProcessor()) {
96+
$operation = $operation->withProcessor($this->getProcessor($operation));
97+
}
98+
99+
return $operation;
100+
}
101+
102+
private function getProvider(AbstractOperation $operation): string
103+
{
104+
if ($operation instanceof CollectionOperationInterface) {
105+
return CollectionProvider::class;
106+
}
107+
108+
return ItemProvider::class;
109+
}
110+
111+
private function getProcessor(AbstractOperation $operation): string
112+
{
113+
if ($operation instanceof DeleteOperationInterface) {
114+
return RemoveProcessor::class;
115+
}
116+
117+
return PersistProcessor::class;
118+
}
119+
}

0 commit comments

Comments
 (0)