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

nextras / orm / 27441222970

12 Jun 2026 08:29PM UTC coverage: 92.051% (-0.1%) from 92.162%
27441222970

Pull #810

github

web-flow
Merge 191dbb3fe into 7a20304be
Pull Request #810: Fix DbalCollection::getQueryBuilder()

61 of 66 new or added lines in 3 files covered. (92.42%)

4 existing lines in 2 files now uncovered.

4273 of 4642 relevant lines covered (92.05%)

5.41 hits per line

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

91.94
/src/Bridges/NetteDI/PhpDocRepositoryFinder.php
1
<?php declare(strict_types = 1);
2

3
namespace Nextras\Orm\Bridges\NetteDI;
4

5

6
use Nette\DI\ContainerBuilder;
7
use Nette\Utils\Reflection;
8
use Nextras\Orm\Entity\IEntity;
9
use Nextras\Orm\Exception\InvalidStateException;
10
use Nextras\Orm\Exception\RuntimeException;
11
use Nextras\Orm\Model\IModel;
12
use Nextras\Orm\Model\Model;
13
use Nextras\Orm\Repository\IRepository;
14
use ReflectionClass;
15

16

17
class PhpDocRepositoryFinder implements IRepositoryFinder
18
{
19
        public function __construct(
5✔
20
                protected readonly string $modelClass,
1✔
21
                protected readonly ContainerBuilder $builder,
1✔
22
                protected readonly OrmExtension $extension,
1✔
23
        )
24
        {
25
        }
6✔
26

27

28
        public function loadConfiguration(): ?array
29
        {
30
                $repositories = $this->findRepositories($this->modelClass);
6✔
31
                $repositoriesMap = [];
6✔
32

33
                foreach ($repositories as $repositoryName => $repositoryClass) {
6✔
34
                        $this->setupMapperService($repositoryName, $repositoryClass);
6✔
35
                        $this->setupRepositoryService($repositoryName, $repositoryClass);
6✔
36
                        $repositoriesMap[$repositoryClass] = $this->extension->prefix('repositories.' . $repositoryName);
6✔
37
                }
38

39
                $this->setupRepositoryLoader($repositoriesMap);
6✔
40
                return $repositories;
6✔
41
        }
42

43

44
        public function beforeCompile(): ?array
45
        {
46
                return null;
6✔
47
        }
48

49

50
        /**
51
         * @param class-string<IModel> $modelClass
52
         * @return array<string, class-string<IRepository<IEntity>>>
53
         */
54
        protected function findRepositories(string $modelClass): array
55
        {
56
                if ($modelClass === Model::class) {
6✔
57
                        throw new InvalidStateException('Your model has to inherit from ' . Model::class . '. Use compiler extension configuration - model key.');
×
58
                }
59

60
                $modelReflection = new ReflectionClass($modelClass);
6✔
61
                $classFileName = $modelReflection->getFileName();
6✔
62
                assert($classFileName !== false);
63
                $this->builder->addDependency($classFileName);
6✔
64

65
                $repositories = [];
6✔
66
                preg_match_all(
6✔
67
                        '~^  [ \t*]*  @property(?:|-read)  [ \t]+  ([^\s$]+)  [ \t]+  \$  (\w+)~mx',
6✔
68
                        (string) $modelReflection->getDocComment(), $matches, PREG_SET_ORDER
6✔
69
                );
70

71
                foreach ($matches as [, $type, $name]) {
6✔
72
                        /** @var class-string<IRepository<IEntity>> $type */
73
                        $type = Reflection::expandClassName($type, $modelReflection); // @phpstan-ignore argument.type (https://github.com/phpstan/phpstan/issues/12459#issuecomment-2607123277)
6✔
74
                        if (!class_exists($type)) {
6✔
75
                                throw new RuntimeException("Repository '{$type}' does not exist.");
×
76
                        }
77

78
                        $rc = new ReflectionClass($type);
6✔
79
                        assert($rc->implementsInterface(IRepository::class), sprintf(
80
                                'Property "%s" of class "%s" with type "%s" does not implement interface %s.',
81
                                $modelClass, $name, $type, IRepository::class
82
                        ));
83

84
                        $repositories[$name] = $type;
6✔
85
                }
86

87
                return $repositories;
6✔
88
        }
89

90

91
        protected function setupMapperService(string $repositoryName, string $repositoryClass): void
92
        {
93
                $mapperName = $this->extension->prefix('mappers.' . $repositoryName);
6✔
94
                if ($this->builder->hasDefinition($mapperName)) {
6✔
95
                        return;
×
96
                }
97

98
                $mapperClass = str_replace('Repository', 'Mapper', $repositoryClass);
6✔
99
                if (!class_exists($mapperClass)) {
6✔
100
                        throw new InvalidStateException("Unknown mapper for '{$repositoryName}' repository.");
×
101
                }
102

103
                /** @var \stdClass $config */
104
                $config = $this->extension->getConfig();
6✔
105
                if ($config->connection !== null) {
6✔
106
                        $connection = ['connection' => $config->connection];
6✔
107
                } else {
108
                        $connection = [];
6✔
109
                }
110

111
                $this->builder->addDefinition($mapperName)
6✔
112
                        ->setType($mapperClass)
6✔
113
                        ->setArguments([
6✔
114
                                'cache' => $this->extension->prefix('@cache'),
6✔
115
                                'mapperCoordinator' => $this->extension->prefix('@mapperCoordinator'),
6✔
116
                        ] + $connection);
6✔
117
        }
6✔
118

119

120
        protected function setupRepositoryService(string $repositoryName, string $repositoryClass): void
121
        {
122
                $serviceName = $this->extension->prefix('repositories.' . $repositoryName);
6✔
123
                if ($this->builder->hasDefinition($serviceName)) {
6✔
UNCOV
124
                        return;
×
125
                }
126

127
                $this->builder->addDefinition($serviceName)
6✔
128
                        ->setType($repositoryClass)
6✔
129
                        ->setArguments([
6✔
130
                                $this->extension->prefix('@mappers.' . $repositoryName),
6✔
131
                                $this->extension->prefix('@dependencyProvider'),
6✔
132
                        ])
133
                        ->addSetup('setModel', [$this->extension->prefix('@model')]);
6✔
134
        }
6✔
135

136

137
        /**
138
         * @param array<class-string<IRepository<IEntity>>, string> $repositoriesMap
139
         */
140
        protected function setupRepositoryLoader(array $repositoriesMap): void
141
        {
142
                $this->builder->addDefinition($this->extension->prefix('repositoryLoader'))
6✔
143
                        ->setType(RepositoryLoader::class)
6✔
144
                        ->setArguments([
6✔
145
                                'repositoryNamesMap' => $repositoriesMap,
6✔
146
                        ]);
147
        }
6✔
148
}
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