Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Serializer] Dynamic DiscriminatorMap and a custom loader registration #50390

Open
ludekbenedik opened this issue May 22, 2023 · 2 comments
Open

Comments

@ludekbenedik
Copy link

ludekbenedik commented May 22, 2023

Description

Symfony does not currently support an easy way to register more mapping types on DiscriminatorMap. This is an important feature for modularity.

Currently a programmer must:

  1. Create a compiler pass to replace first argument of LoaderChain and SerializerCacheWarmer services.
  2. Replace whole ClassDiscriminatorMapping object.

There is a simple change to solve the current not friendly way:

  1. Add serializer.loader tag to register custom loaders.
  2. Add addType(string $type, string $class) method to ClassDiscriminatorMapping class. This point is not important as the first.
  3. Remove internal annotation from ClassMetadataInterface. Is there a reason to mark this class as internal?

For example, Doctrine allows you to dynamically register more types via loadClassMetadata event and ClassMetadataInfo::addDiscriminatorMapClass method.

Example

Before

class SerializerLoadersPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        $chainLoader = $container->getDefinition('serializer.mapping.chain_loader');

        $serializerLoaders = $chainLoader->getArgument(0);
        $serializerLoaders[] = new Definition(DiscriminatorMappingLoader::class, [
            $container->getParameter('module_entity_mapping'), // Define app mapping in configuration
        ]);

        $chainLoader->replaceArgument(0, $serializerLoaders);
        $container->getDefinition('serializer.mapping.cache_warmer')->replaceArgument(0, $serializerLoaders);
    }
}
class DiscriminatorMappingLoader implements LoaderInterface
{
    /**
     * @param array<string, class-string> $appMapping Mapping from configuration
     */
    public function __construct(private array $appMapping)
    {
    }


    public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
    {
        if (ModuleEntity::class === $classMetadata->getName()) {
            $mapping = $classMetadata->getClassDiscriminatorMapping();

            $classMetadata->setClassDiscriminatorMapping(
                new ClassDiscriminatorMapping(
                    $mapping->getTypeProperty(),
                    array_merge($this->appMapping, $mapping->getTypesMapping())
                )
            );

            return true;
        }

        return false;
    }
}

After

return function(ContainerConfigurator $container) {
    $container->services()->set(DiscriminatorMappingLoader::class)
        ->arg(0, abstract_arg('From configuration'))
        ->tag('serializer.loader', ['priority' => 4096])
    ;
};
class DiscriminatorMappingLoader implements LoaderInterface
{
    /**
     * @param array<string, class-string> $appMapping Mapping from configuration
     */
    public function __construct(private array $appMapping)
    {
    }


    public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
    {
        if (ModuleEntity::class === $classMetadata->getName()) {
            $classMetadata->getClassDiscriminatorMapping()->addTypes($this->appMapping);
            // or iterate over appMapping and call addType($type, $class)
            
            return true;
        }

        return false;
    }
}
@carsonbot
Copy link

Thank you for this suggestion.
There has not been a lot of activity here for a while. Would you still like to see this feature?

@ludekbenedik
Copy link
Author

Hi, yes, this feature would be great for modularity.

@carsonbot carsonbot removed the Stalled label Nov 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants