Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Serializer "max_depth" of 1 goes 2 levels deep when encountering a Doctrine Proxy class #58526

Open
@Jalliuz

Description

@Jalliuz

Symfony version(s) affected

6.4

Description

# serialization.yml
App\Entity\Dossier:
    getLinkedDossiers:
        groups:
            - SomeGroup
        max_depth: 1 // This can lead to a very deep structure of linkedDossiers otherwise

Because of the normalizer sometimes encounters Doctrine Proxy classes these 2 classnames each count separately:
See 2 last lines of my dump of $context during normalization:

[
    "groups" => ['SomeGroup'],
    "enable_max_depth" => true,
    "_read_attributes" => true,
    "cache_key" => "8868802559639483b309f315925a74fe-getLinkedDossiers-getLinkedDossiers",
    circular_reference_limit_counters" => [
        "0000000000006a390000000000000000" => 1
    ],
    "depth_App\Entity\Dossier::getLinkedDossiers" => 1
    "depth_Proxies\__CG__\App\Entity\Dossier::getLinkedDossiers" => 1
]

So if I ask max_depth 1 it often only stops on depth 2

How to reproduce

Normalize a Doctrine entity with a LAZY mapping that would normally trigger a Doctrine Proxy class to be generated

#[Route('/dossiers/{dossier}', name: 'get_some_data')]
public function getSomeData(
    Dossier $dossier,
    NormalizerInterface $normalizer,
): JsonResponse {
    $array = $normalizer->normalize($dossier, null, [
        'groups' => [
            'SomeGroup',
        ],
        AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true,
    ]);
}

Possible Solution

I can give the non-serializer solution so a custom fix when working with Doctrine in Symfony. But I wonder if there would be a solution in Symfony or PHP itself to always get the real class? So this fix is not necessary?

Create a CustomObjectClassResolver

<?php
namespace App\Serializer\Service;

use Doctrine\Common\Util\ClassUtils as DoctrineClassUtils;

class CustomObjectClassResolver
{
    /**
     * Fix for max_depth and Doctrine Proxy classes
     * The Symfony serializer handles Doctrine Proxy classes separately from the non-Proxy name
     */
    public function resolveObjectClass(object $object): string
    {
        return DoctrineClassUtils::getRealClass(get_class($object));
    }
}
services:
    Symfony\Component\Serializer\Normalizer\ObjectNormalizer:
        tags:
            # Important! Set priority: -999 to come just before the default Symfony ObjectNormalizer
            # Otherwise, it will come before the DateTimeNormalizer and other specific object normalizers
            # See vendor folder where it gets set to -1000:
            # -> 'serializer.normalizer.object' ... -> ['priority' => -1000]
            - { name: 'serializer.normalizer', priority: -999 }
        bind:
            $objectClassResolver: ['App\Serializer\Service\CustomObjectClassResolver', 'resolveObjectClass']

And then the max_depth works again as expected

Other possible Solution

Make it possible to do something similar like circular_reference_handler and max_depth_handler?

framework:
     serializer:
         default_object_class_resolver: ['My\Class', 'myClassResolverMethod']

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions