Description
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