3

I am unable to override default handlers in jms serializer bundle.

I'd like to change the way Symfony\Component\Validator\ConstraintViolationList is serialized so I wrote my own custom handler. And tagged it correctly as described in the documentation (and in various stackoverflow answers).

However, my handler keeps being overridden by the default handler for ConstraintViolationList that JMS Serializer bundle ships with.

I've tagged my handler service correctly. In fact, my handler service is detected and used correctly when I comment out ms_serializer.constraint_violation_handler service definition from vendor/jms/serializer-bundle/JMS/SerializerBundle/Resources/config/services.xml

How can I stop the default handler from overriding my custom one?

I've even tried overriding jms_serializer.constraint_violation_handler.class parameter from my own bundle but still no luck.

Here is my Handler class:

<?php
namespace Coanda\Bridge\JMSSerializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonSerializationVisitor;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;

class ConstraintViolationHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = [];
        $methods[] = [
            'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
            'type' => ConstraintViolationList::class,
            'format' => 'json',
            'method' => 'serializeListToJson'
        ];
        return $methods;
    }

    public function serializeListToJson(
        JsonSerializationVisitor $visitor,
        ConstraintViolationList $list,
        array $type,
        Context $context
    ) {
        $violations = [];
        foreach ($list as $item) {
            $violations[$item->getPropertyPath()][] = $item->getMessage();
        }
        if (null === $visitor->getRoot()) {
            $visitor->setRoot($violations);
        }
        return $violations;
    }

}

I've registered it in my services.xml

    <service id="coanda.serializer.constraint_violation_handler"
        class="Coanda\Bridge\JMSSerializer\Handler\ConstraintViolationHandler">
        <tag name="jms_serializer.subscribing_handler"
            type="Symfony\Component\Validator\ConstraintViolationList"
            direction="serialization" format="json" method="serializeListToJson" />
    </service>
dnshio
  • 914
  • 1
  • 8
  • 21

3 Answers3

4

This was happening because JMSSerializerBundle was registered after my bundle in AppKernel which meant that whatever service I define will be overridden by JMS Serializer's version of it.

Solution: put your bundle at the very bottom in AppKernel.php like so:

public function registerBundles()
{
    $bundles = [
        // .......
        new JMS\SerializerBundle\JMSSerializerBundle(),
        new My\Bundle\MyAwesomeBundle()
    ];

    return $bundles;
}
dnshio
  • 914
  • 1
  • 8
  • 21
3

For versions

"name": "jms/serializer-bundle",
"version": "3.5.0",

"name": "symfony/framework-bundle",
"version": "v5.0.5",

decision should be like this, 'priority' => -915 should be in getSubscribingMethods

    /**
     * @return array
     */
    public static function getSubscribingMethods()
    {
        return [
            [
                'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
                'format' => 'json',
                'type' => ConstraintViolationList::class,
                'method' => 'serializeCustomListToJson',
                'priority' => -915
            ]
        ];
    }

then \JMS\SerializerBundle\DependencyInjection\Compiler\CustomHandlersPass::sortAndFlattenHandlersList move it in last position and custom servce set in handler instead jms default handler

shuba.ivan
  • 3,824
  • 8
  • 49
  • 121
0

this config work for me:

    exception:
        enabled: true
        serializer_error_renderer: true
Binh Tran
  • 21
  • 1