Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.29% covered (success)
94.29%
33 / 35
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
AutoTagActionsCompilerPass
94.29% covered (success)
94.29%
33 / 35
0.00% covered (danger)
0.00%
0 / 2
12.03
0.00% covered (danger)
0.00%
0 / 1
 process
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
8
 createDefinition
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
4.02
1<?php
2namespace Apie\ApieBundle\DependencyInjection\Compiler;
3
4use Apie\Common\Wrappers\BoundedContextHashmapFactory;
5use Apie\Core\Exceptions\InvalidTypeException;
6use ReflectionClass;
7use ReflectionNamedType;
8use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
9use Symfony\Component\DependencyInjection\ContainerBuilder;
10use Symfony\Component\DependencyInjection\Definition;
11use Symfony\Component\DependencyInjection\Reference;
12use Symfony\Component\EventDispatcher\EventDispatcher;
13
14/**
15 * Actions ony work properly in a Symfony application if they are services with the
16 * tag 'apie.context'.
17 *
18 * This compiler pass makes sure they exist as service definition and contain the tag.
19 */
20class AutoTagActionsCompilerPass implements CompilerPassInterface
21{
22    private const SYMFONY_SERVICES = [
23        'cache_warmer',
24    ];
25    public function process(ContainerBuilder $container): void
26    {
27        $boundedContextConfig = $container->getParameter('apie.bounded_contexts');
28        $scanBoundedContextConfig = $container->getParameter('apie.scan_bounded_contexts');
29        $factory = new BoundedContextHashmapFactory(
30            $boundedContextConfig,
31            $scanBoundedContextConfig,
32            new EventDispatcher()
33        );
34        $hashmap = $factory->create();
35        foreach ($hashmap as $boundedContext) {
36            foreach ($boundedContext->actions as $action) {
37                $class = $action->getDeclaringClass();
38                if (!$class->isInstantiable()) {
39                    continue;
40                }
41                $className = $class->name;
42                if (!$container->hasDefinition($className)) {
43                    $container->addDefinitions([
44                        $className => $this->createDefinition($class)
45                    ]);
46                }
47                $definition = $container->getDefinition($className);
48                $tag = $definition->getTag('apie.context');
49                if (empty($tag)) {
50                    $definition->addTag('apie.context');
51                }
52            }
53        }
54        foreach (self::SYMFONY_SERVICES as $serviceId) {
55            if ($container->hasDefinition($serviceId)) {
56                $definition = $container->getDefinition($serviceId);
57                $definition->addTag('apie.context');
58            }
59        }
60    }
61
62    /**
63     * @param ReflectionClass<object> $refl
64     */
65    private function createDefinition(ReflectionClass $refl): Definition
66    {
67        $arguments = [];
68        $constructor = $refl->getConstructor();
69        if ($constructor) {
70            foreach ($constructor->getParameters() as $parameter) {
71                $type = $parameter->getType();
72                if ($type instanceof ReflectionNamedType) {
73                    $arguments[] = new Reference($type->getName());
74                } else {
75                    throw new InvalidTypeException($type, 'ReflectionNamedType');
76                }
77            }
78        }
79        return new Definition($refl->name, $arguments);
80    }
81}