Incognito
Incognito

Reputation: 20765

Callback argument in symfony service container

I'm working with Symfony's injection container and the Serializer component to provide a service with the default serialization configuration each time. Specifically working with the ObjectNormalizer:

 <service
     id="my_bundle.entity_serializer_normalizer"
     class="Symfony\Component\Serializer\Normalizer\ObjectNormalizer"
 >
     <argument type="service" id="my_bundle.entity_serializer_normalizer_metadata_factory" />
     <argument>null</argument>
     <argument>null</argument>
     <argument type="service" id="my_bundle.entity_serializer_normalizer_reflection_extractor" />

     <call method="setIgnoredAttributes">
         <argument type="collection">
             <argument>__initializer__</argument>
             <argument>__cloner__</argument>
             <argument>__isInitialized__</argument>
         </argument>
     </call>

 </service>

However there is a method on this service I also need to call to set the circular reference handler. In regular PHP this would look like this:

$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getId();
});

However, I can't seem to find a way to add this to a <call> in the container.

I've looked into using the new expression engine feature to try this but it doesn't seem to match up with a callback. I've also pondered if adding a stand-alone function somewhere and registering it would make this work. Right now I'm hacking the method call into the class my serializer is injected into.

I've also attempted manually adding it via a secondary PHP definition:

$container->set(
    'tactic_monolith.entity_serializer_normalizer_circular_reference_handler',
    function ($object) {
        return $object->getId();
    }
);

However it seems to be silently ignored. When doing a setParameter I receive an error (callables cannot be parameters). I have also attempted to register this as a snythetic service.

Upvotes: 3

Views: 1560

Answers (1)

Incognito
Incognito

Reputation: 20765

It seems there's no way to do this without using a factory.

class CircularHandlerFactory
{
    public static function getId(){
        return (function ($object) {
            return $object->getId();
        });
    }
}

and

<service
    id="some_bundle.circular_reference_handler"
    class="callback"
>
    <factory class="SomeBundle\CircularHandlerFactory" method="getId" />
</service>

Finally adding the call to the normalizer:

<call method="setCircularReferenceHandler">
    <argument type="service" id="some_bundle.circular_reference_handler"/>
</call>

In hindsight, perhaps this would have been inappropriate usage of the feature. However, this may also be something worthwhile for a feature request of the expression engine.

Upvotes: 2

Related Questions