api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.45k stars 882 forks source link

Special '*' serialization group #6820

Open SergeyCherenkov opened 6 days ago

SergeyCherenkov commented 6 days ago

Description

The SymfonySerializer has a special group * that allows you to serialize all fields.

https://github.com/symfony/symfony/pull/33540 https://github.com/symfony/symfony/issues/32622 https://github.com/symfony/symfony/commit/de58759a37fc1e268c91bc56da2e77459cb8f2aa

The SerializerPropertyMetadataFactory treats it as a regular group.

namespace ApiPlatform\Metadata\Property\Factory;

final class SerializerPropertyMetadataFactory implements PropertyMetadataFactoryInterface
{
    // ...
    private function transformReadWrite(ApiProperty $propertyMetadata, string $resourceClass, string $propertyName, ?array $normalizationGroups = null, ?array $denormalizationGroups = null): ApiProperty
    {
        $serializerAttributeMetadata = $this->getSerializerAttributeMetadata($resourceClass, $propertyName);
        $groups = $serializerAttributeMetadata ? $serializerAttributeMetadata->getGroups() : [];
        $ignored = $serializerAttributeMetadata && $serializerAttributeMetadata->isIgnored();

        if (false !== $propertyMetadata->isReadable()) {
            $propertyMetadata = $propertyMetadata->withReadable(!$ignored && (null === $normalizationGroups || array_intersect($normalizationGroups, $groups)));
        }

        if (false !== $propertyMetadata->isWritable()) {
            $propertyMetadata = $propertyMetadata->withWritable(!$ignored && (null === $denormalizationGroups || array_intersect($denormalizationGroups, $groups)));
        }

        return $propertyMetadata;
    }
    // ...
}

Wouldn't it be correct to add handling for this group in API Platform?

SergeyCherenkov commented 6 days ago

I propose the following solution (I think it's also applicable for denormalization).

namespace ApiPlatform\Metadata\Property\Factory;

final class SerializerPropertyMetadataFactory implements PropertyMetadataFactoryInterface
{
    // ...
    private function transformReadWrite(ApiProperty $propertyMetadata, string $resourceClass, string $propertyName, ?array $normalizationGroups = null, ?array $denormalizationGroups = null): ApiProperty
    {
        $serializerAttributeMetadata = $this->getSerializerAttributeMetadata($resourceClass, $propertyName);
        $groups = $serializerAttributeMetadata ? $serializerAttributeMetadata->getGroups() : [];
        $groups = array_merge($groups, ['*']); // new line

        $ignored = $serializerAttributeMetadata && $serializerAttributeMetadata->isIgnored();

        if (false !== $propertyMetadata->isReadable()) {
            $propertyMetadata = $propertyMetadata->withReadable(!$ignored && (null === $normalizationGroups || array_intersect($normalizationGroups, $groups)));
        }

        if (false !== $propertyMetadata->isWritable()) {
            $propertyMetadata = $propertyMetadata->withWritable(!$ignored && (null === $denormalizationGroups || array_intersect($denormalizationGroups, $groups)));
        }

        return $propertyMetadata;
    }
    // ...
}

If this is a correct solution, I can create a PR.