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
4 changes: 2 additions & 2 deletions src/JsonLd/Serializer/ItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
} elseif ($this->contextBuilder instanceof AnonymousContextBuilderInterface) {
if ($context['api_collection_sub_level'] ?? false) {
unset($context['api_collection_sub_level']);
$context['output']['genid'] = true;
$context['output']['gen_id'] ??= true;
$context['output']['iri'] = null;
}

Expand All @@ -124,7 +124,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
unset($context['operation'], $context['operation_name']);
}

if (true === ($context['force_iri_generation'] ?? true) && $iri = $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_PATH, $context['operation'] ?? null, $context)) {
if (true === ($context['output']['gen_id'] ?? true) && true === ($context['force_iri_generation'] ?? true) && $iri = $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_PATH, $context['operation'] ?? null, $context)) {
$context['iri'] = $iri;
$metadata['@id'] = $iri;
}
Expand Down
18 changes: 7 additions & 11 deletions src/Serializer/AbstractItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ protected function getAttributeValue(object $object, string $attribute, ?string
&& ($className = $collectionValueType->getClassName())
&& $this->resourceClassResolver->isResourceClass($className)
) {
$childContext = $this->createChildContext($this->createOperationContext($context, $className), $attribute, $format);
$childContext = $this->createChildContext($this->createOperationContext($context, $className, $propertyMetadata), $attribute, $format);

// @see ApiPlatform\Hal\Serializer\ItemNormalizer:getComponents logic for intentional duplicate content
// @see ApiPlatform\JsonApi\Serializer\ItemNormalizer:getComponents logic for intentional duplicate content
Expand Down Expand Up @@ -707,7 +707,7 @@ protected function getAttributeValue(object $object, string $attribute, ?string
($className = $type->getClassName())
&& $this->resourceClassResolver->isResourceClass($className)
) {
$childContext = $this->createChildContext($this->createOperationContext($context, $className), $attribute, $format);
$childContext = $this->createChildContext($this->createOperationContext($context, $className, $propertyMetadata), $attribute, $format);
unset($childContext['iri'], $childContext['uri_variables'], $childContext['item_uri_template']);
if ('jsonld' === $format && $uriTemplate = $propertyMetadata->getUriTemplate()) {
$operation = $this->resourceMetadataCollectionFactory->create($className)->getOperation(
Expand Down Expand Up @@ -749,22 +749,18 @@ protected function getAttributeValue(object $object, string $attribute, ?string

// Anonymous resources
if ($className) {
$childContext = $this->createChildContext($this->createOperationContext($context, $className), $attribute, $format);
$childContext['output']['gen_id'] = $propertyMetadata->getGenId() ?? true;

$childContext = $this->createChildContext($this->createOperationContext($context, $className, $propertyMetadata), $attribute, $format);
$attributeValue = $this->propertyAccessor->getValue($object, $attribute);

return $this->serializer->normalize($attributeValue, $format, $childContext);
}

if ('array' === $type->getBuiltinType()) {
if ($className = ($type->getCollectionValueTypes()[0] ?? null)?->getClassName()) {
$context = $this->createOperationContext($context, $className);
$context = $this->createOperationContext($context, $className, $propertyMetadata);
}

$childContext = $this->createChildContext($context, $attribute, $format);
$childContext['output']['gen_id'] = $propertyMetadata->getGenId() ?? true;

$attributeValue = $this->propertyAccessor->getValue($object, $attribute);

return $this->serializer->normalize($attributeValue, $format, $childContext);
Expand Down Expand Up @@ -820,12 +816,12 @@ protected function normalizeCollectionOfRelations(ApiProperty $propertyMetadata,
*/
protected function normalizeRelation(ApiProperty $propertyMetadata, ?object $relatedObject, string $resourceClass, ?string $format, array $context): \ArrayObject|array|string|null
{
if (null === $relatedObject || !empty($context['attributes']) || $propertyMetadata->isReadableLink()) {
if (null === $relatedObject || !empty($context['attributes']) || $propertyMetadata->isReadableLink() || false === ($context['output']['gen_id'] ?? true)) {
if (!$this->serializer instanceof NormalizerInterface) {
throw new LogicException(\sprintf('The injected serializer must be an instance of "%s".', NormalizerInterface::class));
}

$relatedContext = $this->createOperationContext($context, $resourceClass);
$relatedContext = $this->createOperationContext($context, $resourceClass, $propertyMetadata);
$normalizedRelatedObject = $this->serializer->normalize($relatedObject, $format, $relatedContext);
if (!\is_string($normalizedRelatedObject) && !\is_array($normalizedRelatedObject) && !$normalizedRelatedObject instanceof \ArrayObject && null !== $normalizedRelatedObject) {
throw new UnexpectedValueException('Expected normalized relation to be an IRI, array, \ArrayObject or null');
Expand Down Expand Up @@ -917,7 +913,7 @@ private function createAndValidateAttributeValue(string $attribute, mixed $value
&& $this->resourceClassResolver->isResourceClass($className)
) {
$resourceClass = $this->resourceClassResolver->getResourceClass(null, $className);
$childContext = $this->createChildContext($this->createOperationContext($context, $resourceClass), $attribute, $format);
$childContext = $this->createChildContext($this->createOperationContext($context, $resourceClass, $propertyMetadata), $attribute, $format);

try {
return $this->denormalizeRelation($attribute, $propertyMetadata, $resourceClass, $value, $format, $childContext);
Expand Down
10 changes: 9 additions & 1 deletion src/Serializer/OperationContextTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace ApiPlatform\Serializer;

use ApiPlatform\Metadata\ApiProperty;

/**
* @internal
*/
Expand All @@ -22,7 +24,7 @@ trait OperationContextTrait
* This context is created when working on a relation context or items of a collection. It cleans the previously given
* context as the operation changes.
*/
protected function createOperationContext(array $context, ?string $resourceClass = null): array
protected function createOperationContext(array $context, ?string $resourceClass = null, ?ApiProperty $propertyMetadata = null): array
{
if (isset($context['operation']) && !isset($context['root_operation'])) {
$context['root_operation'] = $context['operation'];
Expand All @@ -34,6 +36,12 @@ protected function createOperationContext(array $context, ?string $resourceClass

unset($context['iri'], $context['uri_variables'], $context['item_uri_template'], $context['force_resource_class']);

// At some point we should merge the jsonld context here, there's a TODO to simplify this somewhere else
if ($propertyMetadata) {
$context['output'] ??= [];
$context['output']['gen_id'] = $propertyMetadata->getGenId() ?? true;
}

if (!$resourceClass) {
return $context;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;

#[ApiResource(operations: [])]
class AggregateRating
{
public function __construct(
#[ApiProperty(iris: ['https://schema.org/ratingValue'])] public float $ratingValue,
#[ApiProperty(iris: ['https://schema.org/ratingCount'])] public int $ratingCount,
) {
}
}
32 changes: 32 additions & 0 deletions tests/Fixtures/TestBundle/ApiResource/GenIdFalse/GenIdFalse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Operation;
use Symfony\Component\Serializer\Attribute\Ignore;

#[Get(uriTemplate: '/gen_id_falsy', provider: [self::class, 'getData'], normalizationContext: ['hydra_prefix' => false])]
class GenIdFalse
{
public function __construct(public string $id, #[ApiProperty(genId: false)] public AggregateRating $aggregateRating, #[Ignore] public string $shouldBeIgnored = 'lala')
{
}

public static function getData(Operation $operation, array $uriVariables = [], array $context = []): self
{
return new self('1', new AggregateRating(2, 3));
}
}
25 changes: 24 additions & 1 deletion tests/Functional/JsonLdTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
namespace ApiPlatform\Tests\Functional;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\AggregateRating;
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\GenIdFalse;
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6810\JsonLdContextOutput;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Bar;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Foo;
Expand All @@ -32,7 +34,7 @@ class JsonLdTest extends ApiTestCase
*/
public static function getResources(): array
{
return [Foo::class, Bar::class, JsonLdContextOutput::class];
return [Foo::class, Bar::class, JsonLdContextOutput::class, GenIdFalse::class, AggregateRating::class];
}

/**
Expand Down Expand Up @@ -67,6 +69,27 @@ public function testContextWithOutput(): void
]);
}

public function testGenIdFalseOnResource(): void
{
$r = self::createClient()->request(
'GET',
'/gen_id_falsy',
);
$this->assertJsonContains([
'aggregateRating' => ['ratingValue' => 2, 'ratingCount' => 3],
]);
$this->assertArrayNotHasKey('@id', $r->toArray()['aggregateRating']);
}

public function testShouldIgnoreProperty(): void
{
$r = self::createClient()->request(
'GET',
'/contexts/GenIdFalse',
);
$this->assertArrayNotHasKey('shouldBeIgnored', $r->toArray()['@context']);
}

protected function setUp(): void
{
self::bootKernel();
Expand Down
Loading