Skip to content

Commit dfb5691

Browse files
committed
fix some tests
1 parent 1614838 commit dfb5691

File tree

12 files changed

+173
-38
lines changed

12 files changed

+173
-38
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@
165165
"symfony/cache": "^6.4 || ^7.0",
166166
"symfony/config": "^6.4 || ^7.0",
167167
"symfony/console": "^6.4 || ^7.0",
168-
"symfony/object-mapper": "^7.3",
169168
"symfony/css-selector": "^6.4 || ^7.0",
170169
"symfony/dependency-injection": "^6.4 || ^7.0",
171170
"symfony/doctrine-bridge": "^6.4.2 || ^7.1",
@@ -181,6 +180,7 @@
181180
"symfony/maker-bundle": "^1.24",
182181
"symfony/mercure-bundle": "*",
183182
"symfony/messenger": "^6.4 || ^7.0",
183+
"symfony/object-mapper": "^7.3",
184184
"symfony/routing": "^6.4 || ^7.0",
185185
"symfony/security-bundle": "^6.4 || ^7.0",
186186
"symfony/security-core": "^6.4 || ^7.0",

src/Doctrine/Odm/Metadata/Property/DoctrineMongoDbOdmPropertyMetadataFactory.php

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use ApiPlatform\Metadata\ApiProperty;
1717
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
18-
use Doctrine\ODM\MongoDB\DocumentManager;
18+
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
1919
use Doctrine\Persistence\ManagerRegistry;
2020

2121
/**
@@ -42,31 +42,23 @@ public function create(string $resourceClass, string $property, array $options =
4242
}
4343

4444
$manager = $this->managerRegistry->getManagerForClass($resourceClass);
45-
if (!$manager instanceof DocumentManager) {
45+
if (!$manager) {
4646
return $propertyMetadata;
4747
}
4848

4949
$doctrineClassMetadata = $manager->getClassMetadata($resourceClass);
50-
$identifiers = $doctrineClassMetadata->getIdentifier();
51-
52-
foreach ($identifiers as $identifier) {
53-
if ($identifier === $property) {
54-
$propertyMetadata = $propertyMetadata->withIdentifier(true);
55-
56-
if (null !== $propertyMetadata->isWritable()) {
57-
break;
58-
}
50+
if (!$doctrineClassMetadata instanceof ClassMetadata) {
51+
return $propertyMetadata;
52+
}
5953

60-
$propertyMetadata = $propertyMetadata->withWritable(false);
54+
if ($doctrineClassMetadata->isIdentifier($property)) {
55+
$propertyMetadata = $propertyMetadata->withIdentifier(true);
6156

62-
break;
57+
if (null === $propertyMetadata->isWritable()) {
58+
$propertyMetadata = $propertyMetadata->withWritable(ClassMetadata::GENERATOR_TYPE_AUTO !== $doctrineClassMetadata->generatorType);
6359
}
6460
}
6561

66-
if (null === $propertyMetadata->isIdentifier()) {
67-
$propertyMetadata = $propertyMetadata->withIdentifier(false);
68-
}
69-
7062
return $propertyMetadata;
7163
}
7264
}

src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface;
2121
use ApiPlatform\Metadata\Operations;
2222
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
23+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\MappedResourceOdm;
2324
use Symfony\Component\Routing\Route;
2425

2526
/**
@@ -43,16 +44,23 @@ public function create(string $resourceClass): ResourceMetadataCollection
4344
$resourceMetadataCollection = $this->decorated->create($resourceClass);
4445
}
4546

47+
// dump($resourceClass);
4648
foreach ($resourceMetadataCollection as $i => $resource) {
4749
/** @var ApiResource $resource */
4850
$resource = $this->configureUriVariables($resource);
51+
// if (MappedResourceOdm::class === $resource->getClass()) {
52+
// dd($resource->getUriVariables());
53+
// }
4954
if ($resource->getUriTemplate()) {
5055
$resourceMetadataCollection[$i] = $resource->withExtraProperties($resource->getExtraProperties() + ['user_defined_uri_template' => true]);
5156
}
5257

5358
$operations = new Operations();
5459
foreach ($resource->getOperations() ?? new Operations() as $key => $operation) {
55-
/** @var HttpOperation */
60+
if (null === $operation->getUriVariables() && !$operation instanceof CollectionOperationInterface) {
61+
$operation = $operation->withUriVariables($resource->getUriVariables());
62+
}
63+
5664
$operation = $this->configureUriVariables($operation);
5765

5866
if (
@@ -153,6 +161,10 @@ private function configureUriVariables(ApiResource|HttpOperation $operation): Ap
153161
}
154162
$operation = $operation->withUriVariables($uriVariables);
155163

164+
// if ($operation instanceof ApiResource && $operation->getClass() === MappedResourceOdm::class) {
165+
//
166+
// dump('ok');
167+
// }
156168
if (str_ends_with($uriTemplate, '{._format}') || str_ends_with($uriTemplate, '.{_format}')) {
157169
$uriTemplate = substr($uriTemplate, 0, -10);
158170
}

src/State/Processor/ObjectMapperProcessor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ final class ObjectMapperProcessor implements ProcessorInterface
2727
* @param ProcessorInterface<mixed,mixed> $decorated
2828
*/
2929
public function __construct(
30-
private readonly ObjectMapperInterface $objectMapper,
30+
private readonly ?ObjectMapperInterface $objectMapper,
3131
private readonly ProcessorInterface $decorated,
3232
) {
3333
}
3434

3535
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): object|array|null
3636
{
37-
if (!$operation->canWrite()) {
37+
if (!$this->objectMapper || !$operation->canWrite()) {
3838
return $this->decorated->process($data, $operation, $uriVariables, $context);
3939
}
4040

src/State/Provider/ObjectMapperProvider.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Doctrine\Odm\State\Options as OdmOptions;
1717
use ApiPlatform\Doctrine\Orm\State\Options;
1818
use ApiPlatform\Metadata\Operation;
19+
use ApiPlatform\Metadata\Util\CloneTrait;
1920
use ApiPlatform\State\Pagination\ArrayPaginator;
2021
use ApiPlatform\State\Pagination\PaginatorInterface;
2122
use ApiPlatform\State\ProviderInterface;
@@ -27,11 +28,13 @@
2728
*/
2829
final class ObjectMapperProvider implements ProviderInterface
2930
{
31+
use CloneTrait;
32+
3033
/**
31-
* @param ProviderInterface<mixed> $decorated
34+
* @param ProviderInterface<object> $decorated
3235
*/
3336
public function __construct(
34-
private readonly ObjectMapperInterface $objectMapper,
37+
private readonly ?ObjectMapperInterface $objectMapper,
3538
private readonly ProviderInterface $decorated,
3639
) {
3740
}
@@ -40,10 +43,11 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
4043
{
4144
$data = $this->decorated->provide($operation, $uriVariables, $context);
4245

43-
if (!\is_object($data)) {
46+
if (!$this->objectMapper || !\is_object($data)) {
4447
return $data;
4548
}
4649

50+
$request = $context['request'] ?? null;
4751
$entityClass = null;
4852
if (($options = $operation->getStateOptions()) && $options instanceof Options && $options->getEntityClass()) {
4953
$entityClass = $options->getEntityClass();
@@ -53,14 +57,21 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5357
$entityClass = $options->getDocumentClass();
5458
}
5559

56-
if (!$entityClass || !(new \ReflectionClass($entityClass))->getAttributes(Map::class)) {
60+
$entityClass ??= $data::class;
61+
62+
if (!(new \ReflectionClass($entityClass))->getAttributes(Map::class)) {
5763
return $data;
5864
}
5965

6066
if ($data instanceof PaginatorInterface) {
61-
return new ArrayPaginator(array_map(fn ($v) => $this->objectMapper->map($v), iterator_to_array($data)), 0, \count($data));
67+
$data = new ArrayPaginator(array_map(fn ($v) => $this->objectMapper->map($v), iterator_to_array($data)), 0, \count($data));
68+
} else {
69+
$data = $this->objectMapper->map($data);
6270
}
6371

64-
return $this->objectMapper->map($data);
72+
$request?->attributes->set('data', $data);
73+
$request?->attributes->set('previous_data', $this->clone($data));
74+
75+
return $data;
6576
}
6677
}

src/State/Provider/ReadProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\State\Provider;
1515

16+
use ApiPlatform\Metadata\CollectionOperationInterface;
1617
use ApiPlatform\Metadata\HttpOperation;
1718
use ApiPlatform\Metadata\Operation;
1819
use ApiPlatform\Metadata\Put;

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
use Symfony\Component\DependencyInjection\Reference;
6060
use Symfony\Component\Finder\Finder;
6161
use Symfony\Component\HttpClient\ScopingHttpClient;
62-
use Symfony\Component\ObjectMapper\Attribute\Map;
62+
use Symfony\Component\ObjectMapper\ObjectMapper;
6363
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
6464
use Symfony\Component\Uid\AbstractUid;
6565
use Symfony\Component\Validator\Validator\ValidatorInterface;
@@ -170,7 +170,7 @@ public function load(array $configs, ContainerBuilder $container): void
170170
$this->registerArgumentResolverConfiguration($loader);
171171
$this->registerLinkSecurityConfiguration($loader, $config);
172172

173-
if (class_exists(Map::class)) {
173+
if (class_exists(ObjectMapper::class)) {
174174
$loader->load('state/object_mapper.xml');
175175
}
176176
$container->registerForAutoconfiguration(FilterInterface::class)

src/Symfony/Bundle/Resources/config/state/object_mapper.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66
<services>
77
<service id="api_platform.state_provider.object_mapper" class="ApiPlatform\State\Provider\ObjectMapperProvider" decorates="api_platform.state_provider.read">
8-
<argument type="service" id="object_mapper" />
8+
<argument type="service" id="object_mapper" on-invalid="null" />
99
<argument type="service" id="api_platform.state_provider.object_mapper.inner" />
1010
</service>
1111

1212
<service id="api_platform.state_processor.object_mapper" class="ApiPlatform\State\Processor\ObjectMapperProcessor" decorates="api_platform.state_processor.locator">
13-
<argument type="service" id="object_mapper" />
13+
<argument type="service" id="object_mapper" on-invalid="null" />
1414
<argument type="service" id="api_platform.state_processor.object_mapper.inner" />
1515
</service>
1616
</services>

tests/Fixtures/TestBundle/ApiResource/MappedResource.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ final class MappedResource
3535

3636
public static function toFirstName(string $v): string
3737
{
38-
return explode(' ', $v)[0] ?? null;
38+
return explode(' ', $v)[0];
3939
}
4040

4141
public static function toLastName(string $v): string
4242
{
43-
return explode(' ', $v)[1] ?? null;
43+
return explode(' ', $v)[1];
4444
}
4545
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\Tests\Fixtures\TestBundle\ApiResource;
15+
16+
use ApiPlatform\Doctrine\Odm\State\Options;
17+
use ApiPlatform\JsonLd\ContextBuilder;
18+
use ApiPlatform\Metadata\ApiResource;
19+
use ApiPlatform\Tests\Fixtures\TestBundle\Document\MappedDocument;
20+
use Symfony\Component\ObjectMapper\Attribute\Map;
21+
22+
#[ApiResource(
23+
stateOptions: new Options(documentClass: MappedDocument::class),
24+
normalizationContext: [ContextBuilder::HYDRA_CONTEXT_HAS_PREFIX => false],
25+
)]
26+
#[Map(target: MappedDocument::class)]
27+
final class MappedResourceOdm
28+
{
29+
#[Map(if: false)]
30+
public ?string $id = null;
31+
32+
#[Map(target: 'firstName', transform: [self::class, 'toFirstName'])]
33+
#[Map(target: 'lastName', transform: [self::class, 'toLastName'])]
34+
public string $username;
35+
36+
public static function toFirstName(string $v): string
37+
{
38+
return explode(' ', $v)[0];
39+
}
40+
41+
public static function toLastName(string $v): string
42+
{
43+
return explode(' ', $v)[1];
44+
}
45+
}

0 commit comments

Comments
 (0)