• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ICanBoogie / bind-routing / 4517953600

pending completion
4517953600

push

github

Olivier Laviale
Automatically register controllers as services

33 of 33 new or added lines in 1 file covered. (100.0%)

82 of 139 relevant lines covered (58.99%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/ActionResponderCompilerPass.php
1
<?php
2

3
namespace ICanBoogie\Binding\Routing;
4

5
use ICanBoogie\Binding\Routing\Attribute\ActionResponder;
6
use ICanBoogie\Binding\Routing\Attribute\Route;
7
use olvlvl\ComposerAttributeCollector\Attributes;
8
use olvlvl\ComposerAttributeCollector\TargetMethod;
9
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
10
use Symfony\Component\DependencyInjection\ContainerBuilder;
11
use Symfony\Component\DependencyInjection\Definition;
12

13
use function array_fill_keys;
14
use function array_keys;
15
use function class_exists;
16
use function ICanBoogie\iterable_to_groups;
17
use function in_array;
18

19
/**
20
 * Registers controller services, and set the tags 'action_responder' and 'action_alias' according to attributes.
21
 */
22
final class ActionResponderCompilerPass implements CompilerPassInterface
23
{
24
    public const TAG = 'action_responder';
25

26
    public function process(ContainerBuilder $container): void
27
    {
28
        if (!class_exists(Attributes::class)) {
×
29
            return;
×
30
        }
31

32
        $target_methods_by_class = $this->find_target_methods_by_class();
×
33
        $this->process_controllers($container, $target_methods_by_class);
×
34
    }
35

36
    /**
37
     * @return array<class-string, iterable<TargetMethod<Route>>>
38
     */
39
    private function find_target_methods_by_class(): array
40
    {
41
        /** @phpstan-ignore-next-line */
42
        return iterable_to_groups(
×
43
            Attributes::filterTargetMethods(
×
44
                Attributes::predicateForAttributeInstanceOf(Route::class)
×
45
            ),
×
46
            fn(TargetMethod $t) => $t->class
×
47
        );
×
48
    }
49

50
    /**
51
     * Registers controllers with the class attributes {@link Route} or {@link ActionResponder}.
52
     *
53
     * @param array<class-string, iterable<TargetMethod<Route>>> $target_methods_by_class
54
     */
55
    private function process_controllers(ContainerBuilder $container, array $target_methods_by_class): void
56
    {
57
        foreach ($this->find_controllers_classes(array_keys($target_methods_by_class)) as $class) {
×
58
            $definition = $this->ensure_definition($class, $container);
×
59

60
            if (!$definition->hasTag(self::TAG)) {
×
61
                $definition->addTag(self::TAG);
×
62
            }
63

64
            $this->tag_aliases($definition, $target_methods_by_class[$class] ?? []);
×
65
        }
66
    }
67

68
    /**
69
     * @param iterable<TargetMethod<Route>> $target_methods
70
     */
71
    private function tag_aliases(Definition $definition, iterable $target_methods): void
72
    {
73
        foreach ($target_methods as $tm) {
×
74
            $action = $tm->attribute->action
×
75
                ?? ActionResolver::resolve_action($tm->class, $tm->name);
×
76

77
            $definition->addTag(ActionAliasCompilerPass::TAG, [ ActionAliasCompilerPass::TAG_KEY => $action ]);
×
78
        }
79
    }
80

81
    /**
82
     * Ensures the controller service is defined.
83
     *
84
     * @param class-string $class
85
     */
86
    private function ensure_definition(string $class, ContainerBuilder $container): Definition
87
    {
88
        if ($container->hasDefinition($class)) {
×
89
            return $container->getDefinition($class);
×
90
        }
91

92
        $definition = new Definition($class);
×
93
        $definition->setAutowired(true);
×
94
        $definition->setShared(false);
×
95

96
        $container->setDefinition($class, $definition);
×
97

98
        return $definition;
×
99
    }
100

101
    /**
102
     * @param array<class-string> $classes
103
     *     Classes already found from target methods.
104
     *
105
     * @return array<class-string>
106
     */
107
    private function find_controllers_classes(array $classes): array
108
    {
109
        $classes = array_fill_keys($classes, true);
×
110

111
        $target_classes = Attributes::filterTargetClasses(
×
112
            fn(string $attribute): bool => in_array($attribute, [ Route::class, ActionResponder::class ])
×
113
        );
×
114

115
        foreach ($target_classes as $target_class) {
×
116
            $classes[$target_class->name] = true;
×
117
        }
118

119
        return array_keys($classes);
×
120
    }
121
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc