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

nextras / orm / 15215831950

23 May 2025 05:24PM UTC coverage: 91.709% (-0.02%) from 91.73%
15215831950

Pull #744

github

web-flow
Merge 5770ec436 into 0facb0de2
Pull Request #744: Force initialization for Nette DI's lazy mode [closes #743]

0 of 2 new or added lines in 2 files covered. (0.0%)

1 existing line in 1 file now uncovered.

4115 of 4487 relevant lines covered (91.71%)

4.57 hits per line

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

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

3
namespace Nextras\Orm\Bridges\NetteDI;
4

5

6
use Nette\Caching\Cache;
7
use Nette\DI\CompilerExtension;
8
use Nette\DI\ContainerBuilder;
9
use Nette\Schema\Expect;
10
use Nette\Schema\Schema;
11
use Nextras\Dbal\IConnection;
12
use Nextras\Orm\Entity\IEntity;
13
use Nextras\Orm\Entity\Reflection\IMetadataParserFactory;
14
use Nextras\Orm\Entity\Reflection\MetadataParser;
15
use Nextras\Orm\Exception\InvalidStateException;
16
use Nextras\Orm\Mapper\Dbal\DbalMapperCoordinator;
17
use Nextras\Orm\Model\IModel;
18
use Nextras\Orm\Model\MetadataStorage;
19
use Nextras\Orm\Model\Model;
20
use Nextras\Orm\Repository\IRepository;
21
use stdClass;
22
use function is_subclass_of;
23

24

25
/**
26
 * @property-read stdClass $config
27
 */
28
class OrmExtension extends CompilerExtension
29
{
30
        protected ContainerBuilder $builder;
31

32
        protected IRepositoryFinder $repositoryFinder;
33

34
        /** @var class-string<IModel> */
35
        protected string $modelClass;
36

37

38
        public function getConfigSchema(): Schema
39
        {
40
                return Expect::structure([
5✔
41
                        'model' => Expect::string()->default(Model::class),
5✔
42
                        'repositoryFinder' => Expect::string()->default(PhpDocRepositoryFinder::class),
5✔
43
                        'initializeMetadata' => Expect::bool()->default(false),
5✔
44
                        'autowiredInternalServices' => Expect::bool()->default(true),
5✔
45
                        'connection' => Expect::string(),
5✔
46
                ]);
47
        }
48

49

50
        public function loadConfiguration(): void
51
        {
52
                $this->builder = $this->getContainerBuilder();
5✔
53
                $this->modelClass = $this->config->model;
5✔
54

55
                $repositoryFinderClass = $this->config->repositoryFinder;
5✔
56
                if (!is_subclass_of($repositoryFinderClass, IRepositoryFinder::class)) {
5✔
57
                        throw new InvalidStateException('Repository finder does not implement Nextras\Orm\Bridges\NetteDI\IRepositoryFinder interface.');
×
58
                }
59
                $this->repositoryFinder = new $repositoryFinderClass($this->modelClass, $this->builder, $this);
5✔
60

61
                $repositories = $this->repositoryFinder->loadConfiguration();
5✔
62

63
                $this->setupCache();
5✔
64
                $this->setupDependencyProvider();
5✔
65
                $this->setupDbalMapperDependencies();
5✔
66
                $this->setupMetadataParserFactory();
5✔
67

68
                if ($repositories !== null) {
5✔
69
                        $repositoriesConfig = Model::getConfiguration($repositories);
5✔
70
                        $this->setupMetadataStorage($repositoriesConfig[2]);
5✔
71
                        $this->setupModel($this->modelClass, $repositoriesConfig);
5✔
72
                }
73

74
                $this->initializeMetadata($this->config->initializeMetadata);
5✔
75
        }
5✔
76

77

78
        public function beforeCompile(): void
79
        {
80
                $repositories = $this->repositoryFinder->beforeCompile();
5✔
81

82
                if ($repositories !== null) {
5✔
83
                        $repositoriesConfig = Model::getConfiguration($repositories);
5✔
84
                        $this->setupMetadataStorage($repositoriesConfig[2]);
5✔
85
                        $this->setupModel($this->modelClass, $repositoriesConfig);
5✔
86
                }
87

88
                $this->setupDbalMapperDependencies();
5✔
89
        }
5✔
90

91

92
        protected function setupCache(): void
93
        {
94
                $cacheName = $this->prefix('cache');
5✔
95
                if ($this->builder->hasDefinition($cacheName)) {
5✔
96
                        return;
×
97
                }
98

99
                $this->builder->addDefinition($cacheName)
5✔
100
                        ->setType(Cache::class)
5✔
101
                        ->setArguments([
5✔
102
                                'namespace' => $this->name,
5✔
103
                        ])
104
                        ->setAutowired(false);
5✔
105
        }
5✔
106

107

108
        protected function setupDependencyProvider(): void
109
        {
110
                $providerName = $this->prefix('dependencyProvider');
5✔
111
                if ($this->builder->hasDefinition($providerName)) {
5✔
112
                        return;
×
113
                }
114

115
                $this->builder->addDefinition($providerName)
5✔
116
                        ->setType(DependencyProvider::class)
5✔
117
                        ->setAutowired($this->config->autowiredInternalServices);
5✔
118
        }
5✔
119

120

121
        protected function setupDbalMapperDependencies(): void
122
        {
123
                if (count($this->builder->findByType(IConnection::class)) === 0) {
5✔
124
                        return;
5✔
125
                }
126

127
                $name = $this->prefix('mapperCoordinator');
5✔
128
                if ($this->builder->hasDefinition($name)) {
5✔
129
                        return;
5✔
130
                }
131

132
                $this->builder->addDefinition($name)
5✔
133
                        ->setType(DbalMapperCoordinator::class)
5✔
134
                        ->setArguments(
5✔
135
                                $this->config->connection !== null ? ['connection' => $this->config->connection] : [],
5✔
136
                        )
137
                        ->setAutowired($this->config->autowiredInternalServices);
5✔
138
        }
5✔
139

140

141
        protected function setupMetadataParserFactory(): void
142
        {
143
                $factoryName = $this->prefix('metadataParserFactory');
5✔
144
                if ($this->builder->hasDefinition($factoryName)) {
5✔
145
                        return;
×
146
                }
147

148
                $this->builder->addFactoryDefinition($factoryName)
5✔
149
                        ->setImplement(IMetadataParserFactory::class)
5✔
150
                        ->getResultDefinition()
5✔
151
                        ->setType(MetadataParser::class)
5✔
152
                        ->setArguments(['$entityClassesMap'])
5✔
153
                        ->setAutowired($this->config->autowiredInternalServices);
5✔
154
        }
5✔
155

156

157
        /**
158
         * @param array<class-string<IEntity>, class-string<IRepository<IEntity>>> $entityClassMap
159
         */
160
        protected function setupMetadataStorage(array $entityClassMap): void
161
        {
162
                $metadataName = $this->prefix('metadataStorage');
5✔
163
                if ($this->builder->hasDefinition($metadataName)) {
5✔
164
                        return;
×
165
                }
166

167
                $this->builder->addDefinition($metadataName)
5✔
168
                        ->setType(MetadataStorage::class)
5✔
169
                        ->setArguments([
5✔
170
                                'entityClassesMap' => $entityClassMap,
5✔
171
                                'cache' => $this->prefix('@cache'),
5✔
172
                                'metadataParserFactory' => $this->prefix('@metadataParserFactory'),
5✔
173
                                'repositoryLoader' => $this->prefix('@repositoryLoader'),
5✔
174
                        ])
175
                        ->setAutowired($this->config->autowiredInternalServices);
5✔
176
        }
5✔
177

178

179
        /**
180
         * @param array{
181
         *     array<class-string<IRepository<IEntity>>, true>,
182
         *     array<string, class-string<IRepository<IEntity>>>,
183
         *     array<class-string<IEntity>, class-string<IRepository<IEntity>>>
184
         *     } $repositoriesConfig
185
         */
186
        protected function setupModel(string $modelClass, array $repositoriesConfig): void
187
        {
188
                $modelName = $this->prefix('model');
5✔
189
                if ($this->builder->hasDefinition($modelName)) {
5✔
190
                        return;
×
191
                }
192

193
                $this->builder->addDefinition($modelName)
5✔
194
                        ->setType($modelClass)
5✔
195
                        ->setArguments([
5✔
196
                                'configuration' => $repositoriesConfig,
5✔
197
                                'repositoryLoader' => $this->prefix('@repositoryLoader'),
5✔
198
                                'metadataStorage' => $this->prefix('@metadataStorage'),
5✔
199
                        ]);
200
        }
5✔
201

202

203
        protected function initializeMetadata(bool $init): void
204
        {
205
                if (!$init) {
5✔
206
                        return;
5✔
207
                }
208

209
                // getMetadata() to force initialization when Nette DI's lazy proxies are enabled.
NEW
210
                $this->initialization->addBody('$this->getService(?)->getLoadedMetadata();', [
×
UNCOV
211
                        $this->prefix('metadataStorage'),
×
212
                ]);
213
        }
×
214
}
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