Skip to content

Commit 0f1360e

Browse files
committed
fix(jsonld): various json streamer fixes
1 parent 6db55be commit 0f1360e

File tree

3 files changed

+70
-12
lines changed

3 files changed

+70
-12
lines changed

src/JsonLd/JsonStreamer/ValueTransformer/TypeValueTransformer.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,54 @@
1515

1616
use ApiPlatform\Hydra\Collection;
1717
use ApiPlatform\Metadata\Exception\RuntimeException;
18+
use ApiPlatform\Metadata\HttpOperation;
19+
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
20+
use ApiPlatform\Metadata\ResourceClassResolverInterface;
1821
use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface;
1922
use Symfony\Component\TypeInfo\Type;
2023

2124
final class TypeValueTransformer implements ValueTransformerInterface
2225
{
26+
public function __construct(
27+
private readonly ResourceClassResolverInterface $resourceClassResolver,
28+
private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory,
29+
) {
30+
}
31+
2332
public function transform(mixed $value, array $options = []): mixed
2433
{
25-
if ($options['_current_object'] instanceof Collection) {
34+
if ($options['_current_object'] instanceof Collection || !\is_object($options['_current_object'])) {
2635
return 'Collection';
2736
}
2837

29-
if (!isset($options['operation'])) {
30-
throw new RuntimeException('Operation is not defined');
38+
if (($currentClass = $options['_current_object']::class) === $options['data']::class) {
39+
if (!isset($options['operation'])) {
40+
throw new RuntimeException('Operation is not defined');
41+
}
42+
43+
return $this->getOperationType($options['operation']);
44+
}
45+
46+
if (!$this->resourceClassResolver->isResourceClass($currentClass)) {
47+
return null;
3148
}
3249

33-
return $options['operation']->getShortName();
50+
$op = $this->resourceMetadataCollectionFactory->create($currentClass)->getOperation(httpOperation: true);
51+
52+
return $this->getOperationType($op);
3453
}
3554

3655
public static function getStreamValueType(): Type
3756
{
3857
return Type::string();
3958
}
59+
60+
private function getOperationType(HttpOperation $operation): array|string
61+
{
62+
if (($t = $operation->getTypes()) && 1 === \count($t)) {
63+
return $operation->getTypes()[0];
64+
}
65+
66+
return $t ?: $operation->getShortname();
67+
}
4068
}

src/JsonLd/JsonStreamer/WritePropertyMetadataLoader.php

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
use ApiPlatform\Hydra\Collection;
1717
use ApiPlatform\Hydra\IriTemplate;
18+
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
19+
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
1820
use ApiPlatform\Metadata\ResourceClassResolverInterface;
1921
use ApiPlatform\Metadata\Util\TypeHelper;
2022
use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata;
@@ -26,6 +28,8 @@ final class WritePropertyMetadataLoader implements PropertyMetadataLoaderInterfa
2628
public function __construct(
2729
private readonly PropertyMetadataLoaderInterface $loader,
2830
private readonly ResourceClassResolverInterface $resourceClassResolver,
31+
private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory,
32+
private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory,
2933
) {
3034
}
3135

@@ -47,23 +51,45 @@ public function load(string $className, array $options = [], array $context = []
4751
return $properties;
4852
}
4953

50-
$properties['@id'] = new PropertyMetadata(
51-
'id', // virtual property
52-
Type::mixed(), // virtual property
53-
['api_platform.jsonld.json_streamer.write.value_transformer.iri'],
54-
);
54+
$originalClassName = TypeHelper::getClassName($context['original_type']);
55+
$hasIri = true;
56+
$virtualProperty = 'id';
57+
58+
if ($className !== $originalClassName) {
59+
foreach ($this->propertyNameCollectionFactory->create($originalClassName) as $property) {
60+
$propertyMetadata = $this->propertyMetadataFactory->create($originalClassName, $property);
61+
if ($propertyMetadata->isIdentifier()) {
62+
$virtualProperty = $property;
63+
}
64+
65+
if ($propertyMetadata->getNativeType()->isIdentifiedBy($className)) {
66+
$hasIri = $propertyMetadata->getGenId();
67+
$virtualProperty = iterator_to_array($this->propertyNameCollectionFactory->create($className))[0];
68+
}
69+
}
70+
}
71+
72+
if ($hasIri) {
73+
$properties['@id'] = new PropertyMetadata(
74+
$virtualProperty, // virtual property
75+
Type::mixed(), // virtual property
76+
['api_platform.jsonld.json_streamer.write.value_transformer.iri'],
77+
);
78+
}
5579

5680
$properties['@type'] = new PropertyMetadata(
57-
'id', // virtual property
81+
$virtualProperty, // virtual property
5882
Type::mixed(), // virtual property
5983
['api_platform.jsonld.json_streamer.write.value_transformer.type'],
6084
);
6185

62-
$originalClassName = TypeHelper::getClassName($context['original_type']);
86+
if ($className !== $originalClassName) {
87+
return $properties;
88+
}
6389

6490
if (Collection::class === $originalClassName || ($this->resourceClassResolver->isResourceClass($originalClassName) && !isset($context['generated_classes'][Collection::class]))) {
6591
$properties['@context'] = new PropertyMetadata(
66-
'id', // virual property
92+
$virtualProperty, // virual property
6793
Type::string(), // virtual property
6894
['api_platform.jsonld.json_streamer.write.value_transformer.context'],
6995
);

src/Symfony/Bundle/Resources/config/json_streamer/common.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
<service id="api_platform.jsonld.json_streamer.write.property_metadata_loader" class="ApiPlatform\JsonLd\JsonStreamer\WritePropertyMetadataLoader">
2020
<argument type="service" id="json_streamer.write.property_metadata_loader" />
2121
<argument type="service" id="api_platform.resource_class_resolver" />
22+
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
23+
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
2224
</service>
2325

2426
<service id="api_platform.jsonld.json_streamer.write.value_transformer.iri" class="ApiPlatform\JsonLd\JsonStreamer\ValueTransformer\IriValueTransformer">
@@ -27,6 +29,8 @@
2729
</service>
2830

2931
<service id="api_platform.jsonld.json_streamer.write.value_transformer.type" class="ApiPlatform\JsonLd\JsonStreamer\ValueTransformer\TypeValueTransformer">
32+
<argument type="service" id="api_platform.resource_class_resolver" />
33+
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
3034
<tag name="json_streamer.value_transformer"/>
3135
</service>
3236

0 commit comments

Comments
 (0)