Reputation: 1047
I made simple API bundle which is(will be) shared among the projects. Every object/entity has its own configuration that says which fields and how they're gonna be serialized(decomposed to scalar values). How they're gonna be serialized depends on selected normalizer. Right now there is only one default normalizer that recognize value as scalar, iterable or object. So far it works great. When you need some specific serialization like for DateTime (where you don't want decompose object to implicit scalar values, but set output format), you just make a new normalizer that process that object accordingly.
Since which normalizer to use is defined in configuration yaml file and can be passed from other sources, name of normalizer must be a string.
App\Entity\Example\Category:
normalizer: asyf.api.service.normalizer.default
fields:
title:
expose: true
slug:
expose: false
items:
orderBy:
title:
priority: 1
direction: DESC
limit: 2
expose: true
Normalizers are tagged as "asyf.api.normalizer". As this is created as vendor bundle I used it's dependency injection extension to load services by tag and inject them to NormalizersManager service that stores them and can revive them by key name
class AsyfApiExtension extends Extension
{
/**
* @param array $configs
* @param ContainerBuilder $container
*
* @throws \Exception
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$container->setParameter('asyf_api', $config);
$normalizerManagerDefinition = $container->findDefinition('asyf.api.service.normalizers_manager');
$defaultNormalizerId = 'asyf.api.service.normalizer.default';
$defaultNormalizerReference = new Reference($defaultNormalizerId);
$normalizerManagerDefinition->addMethodCall('add', array($defaultNormalizerId, $defaultNormalizerReference));
$taggedNormalizers = $container->findTaggedServiceIds('asyf.api.normalizer');
foreach ($taggedNormalizers as $id => $tags) {
$normalizerReference = new Reference($id);
$normalizerManagerDefinition->addMethodCall('add', array($id, $normalizerReference));
}
}
}
Now to the problem: This container in AsyfApiExtension::load cannot see tagged services outside its scope. It's just seeing services defined in this bundle. So when I create new autowired normalizer and register it in config/services.yaml with tag, vendor bundle doesn't see it and it's not added to NormalizersManager service, therefore it cannot be used.
App\Service\Search\Normalizer\SearchResultNormalizer:
public: true
tags:
- { name: 'asyf.api.normalizer' }
To solve this I can add it manually but then I loose this automatic configuration thought. Is there a way to make new autowired normalizers accessible in vendor extension load? Thx for any ideas
Upvotes: 1
Views: 609
Reputation: 1047
I have found a solution, I have to rewrite a bit of my code but here it is:
asyf.api.service.normalizers_manager:
class: App\Service\Search\NormalizersManager
arguments: [!tagged asyf.api.normalizer]
!tagged asyf.api.normalizer
injects a collection of services with tag asyf.api.normalizer
Upvotes: 2