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

tito10047 / type-safe-id-bundle / 23182491396

17 Mar 2026 07:03AM UTC coverage: 86.0% (+7.4%) from 78.621%
23182491396

push

github

tito10047
change multiple servises to one global

115 of 120 new or added lines in 3 files covered. (95.83%)

1 existing line in 1 file now uncovered.

172 of 200 relevant lines covered (86.0%)

27.75 hits per line

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

93.18
/src/EntityIdTypeRegisterCompilerPass.php
1
<?php
2

3
namespace Tito10047\TypeSafeIdBundle;
4

5
use Symfony\Bridge\Doctrine\Types\AbstractUidType;
6
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
7
use Symfony\Component\DependencyInjection\ContainerBuilder;
8
use Symfony\Component\DependencyInjection\Definition;
9
use Symfony\Component\DependencyInjection\Reference;
10
use Symfony\Component\Uid\Ulid;
11
use Symfony\Component\Uid\Uuid;
12
use League\ConstructFinder\ConstructFinder;
13
use Tito10047\TypeSafeIdBundle\IdGenerator\UniversalTypeIdGenerator;
14

15
class EntityIdTypeRegisterCompilerPass implements CompilerPassInterface {
16

17
        private const CONTAINER_TYPES_PARAMETER = 'doctrine.dbal.connection_factory.types';
18

19
        public function __construct(
20
                private string $projectDir,
21
        ) {
22
        }
36✔
23

24
        public function process(ContainerBuilder $container): void
25
        {
26
                // throw new \Exception('CompilerPass is running');
27
                if (!$container->hasParameter('type_safe_id.entity_path')) {
36✔
NEW
28
                        return;
×
29
                }
30

31
                /** @var array<string, array{class: class-string}> $typeDefinition */
32
                $typeDefinition = $container->getParameter(self::CONTAINER_TYPES_PARAMETER);
36✔
33

34
                $entityNamespace = $this->pathToNamespace($container->getParameter('type_safe_id.entity_path'));
36✔
35
                $typeIdNamespace = $this->pathToNamespace($container->getParameter('type_safe_id.type_id_path'));
36✔
36

37
                $types = $this->generateTypes($container, $container->getParameter('type_safe_id.type_id_path'));
36✔
38

39
                // Build entity -> ID class mapping for universal generator
40
                $entityToIdClassMap = [];
36✔
41

42
                /** @var array{namespace: string, name: string, id_class: string} $type */
43
                foreach ($types as $type) {
36✔
44
                        $name      = $type['name'];
36✔
45
                        $namespace = $type['namespace'];
36✔
46
                        $idClass   = $type['id_class'];
36✔
47

48
                        if (array_key_exists($name, $typeDefinition)) {
36✔
UNCOV
49
                                continue;
×
50
                        }
51

52
                        $typeDefinition[$name] = ['class' => $namespace];
36✔
53

54
                        // Build mapping: Entity class -> ID class
55
                        if ($idClass) {
36✔
56
                                // Convert App\Domain\ValueObject\ProductId to App\Domain\Entity\Product
57
                                $entityClass = str_replace($typeIdNamespace, $entityNamespace, $idClass);
36✔
58
                                $entityClass = preg_replace('/Id$/', '', $entityClass);
36✔
59

60
                                $entityToIdClassMap[$entityClass] = $idClass;
36✔
61
                        }
62
                }
63

64
                // Register single universal ID generator service with the mapping
65
                if (!empty($entityToIdClassMap)) {
36✔
66
                        $generatorDefinition = new Definition(UniversalTypeIdGenerator::class, [$entityToIdClassMap]);
36✔
67
                        $generatorDefinition->setPublic(false);
36✔
68
                        $generatorDefinition->addTag('doctrine.id_generator');
36✔
69
                        $container->setDefinition('doctrine.id_generator.universal', $generatorDefinition);
36✔
70
                }
71

72
                $container->setParameter(self::CONTAINER_TYPES_PARAMETER, $typeDefinition);
36✔
73
        }
74

75
        /** @return iterable<int, array{namespace: class-string, name: string, id_class: string}> */
76
        private function generateTypes(ContainerBuilder $container, string $typeIdPath): iterable
77
        {
78
                $searchPath = sprintf('%s/%s', $this->projectDir, $typeIdPath);
36✔
79
                if (!is_dir($searchPath)) {
36✔
NEW
80
                        return;
×
81
                }
82

83
                $classNames = ConstructFinder::locatedIn($searchPath)->findClassNames();
36✔
84

85
                foreach ($classNames as $className) {
36✔
86
                        $reflection = new \ReflectionClass($className);
36✔
87

88
                        if (! $reflection->isSubclassOf(AbstractUidType::class) && !$reflection->isSubclassOf(AbstractIntIdType::class) ) {
36✔
89
                                continue;
36✔
90
                        }
91

92
                        // Find the corresponding entity ID class
93
                        $idClass = null;
36✔
94
                        if (str_ends_with($className, 'Type')) {
36✔
95
                                $idClass = substr($className, 0, -4); // Remove 'Type' suffix
36✔
96
                        }
97

98
                        yield [
36✔
99
                                'namespace' => $reflection->getName(),
36✔
100
                                'name'      => $reflection->getName(),
36✔
101
                                'id_class'  => $idClass,
36✔
102
                        ];
36✔
103
                }
104
        }
105

106
        private function pathToNamespace(string $path): string
107
        {
108
                $namespace = preg_replace('/^src\//', '', $path);
36✔
109
                $namespace = str_replace('/', '\\', $namespace);
36✔
110
                return trim($namespace, '\\');
36✔
111
        }
112
}
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