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

brick / orm / 23255296146

18 Mar 2026 04:24PM UTC coverage: 47.104%. Remained the same
23255296146

push

github

BenMorel
Avoid \Exception that somehow confuses ECS

1 of 5 new or added lines in 1 file covered. (20.0%)

402 existing lines in 24 files now uncovered.

553 of 1174 relevant lines covered (47.1%)

10.6 hits per line

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

0.0
/src/Configuration.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\ORM;
6

7
use InvalidArgumentException;
8
use LogicException;
9

10
use function array_values;
11
use function sprintf;
12
use function str_replace;
13
use function strlen;
14
use function strrpos;
15
use function substr;
16

17
use const DIRECTORY_SEPARATOR;
18

19
class Configuration
20
{
21
    private ?string $proxyNamespace = null;
22

23
    private ?string $proxyDir = null;
24

25
    private ?string $repositoryNamespace = null;
26

27
    private ?string $repositoryDir = null;
28

29
    private ?string $classMetadataFile = null;
30

31
    private ?string $baseEntityNamespace = null;
32

33
    /**
34
     * @var array<class-string, ClassConfiguration>
35
     */
36
    private array $classes = [];
37

38
    /**
39
     * A map of entity/embeddable class names to lists of transient property names.
40
     *
41
     * @var array<class-string, list<string>>
42
     */
43
    private array $transientProperties = [];
44

45
    /**
46
     * A map of entity/embeddable class names to property names to PropertyMapping instances.
47
     *
48
     * The mappings are usually inferred from the PHP type, but can be overridden here.
49
     * This is typically used to map a mixed/array type property to a JSON column.
50
     *
51
     * @var array<class-string, array<string, PropertyMapping>>
52
     */
53
    private array $customPropertyMappings = [];
54

55
    /**
56
     * A map of entity/embeddable class names to property names to field names.
57
     *
58
     * @var array<class-string, array<string, string>>
59
     */
60
    private array $fieldNames = [];
61

62
    /**
63
     * A map of entity/embeddable class names to property names to field name prefixes.
64
     *
65
     * @var array<class-string, array<string, string>>
66
     */
67
    private array $fieldNamePrefixes = [];
68

69
    /**
70
     * A map of class names to custom property mapping classes.
71
     *
72
     * @var array<string, class-string<PropertyMapping>>
73
     */
74
    private array $customMappings = [];
75

76
    public function setProxyNamespace(string $proxyNamespace): Configuration
77
    {
78
        $this->proxyNamespace = $proxyNamespace;
×
79

UNCOV
80
        return $this;
×
81
    }
82

83
    /**
84
     * @throws LogicException
85
     */
86
    public function getProxyNamespace(?string $entityClass = null): string
87
    {
UNCOV
88
        if ($this->proxyNamespace === null) {
×
UNCOV
89
            throw new LogicException('Proxy namespace is not set.');
×
90
        }
91

UNCOV
92
        if ($entityClass === null) {
×
UNCOV
93
            return $this->proxyNamespace;
×
94
        }
95

96
        if ($this->baseEntityNamespace !== null) {
×
UNCOV
97
            $baseNamespace = $this->baseEntityNamespace . '\\';
×
98
            $length = strlen($baseNamespace);
×
99

UNCOV
100
            if (substr($entityClass, 0, $length) !== $baseNamespace) {
×
UNCOV
101
                throw new LogicException(sprintf('%s is not in namespace %s.', $entityClass, $this->baseEntityNamespace));
×
102
            }
103

UNCOV
104
            $entityClass = substr($entityClass, $length);
×
105
        }
106

107
        $pos = strrpos($entityClass, '\\');
×
108

UNCOV
109
        if ($pos === false) {
×
UNCOV
110
            return $this->proxyNamespace;
×
111
        }
112

UNCOV
113
        return $this->proxyNamespace . '\\' . substr($entityClass, 0, $pos);
×
114
    }
115

116
    /**
117
     * Returns the proxy class name for the given entity class name.
118
     *
119
     * @param class-string $entityClass The FQCN of the entity.
120
     *
121
     * @return class-string<Proxy> The FQCN of the proxy.
122
     *
123
     * @throws LogicException
124
     */
125
    public function getProxyClassName(string $entityClass): string
126
    {
UNCOV
127
        if ($this->baseEntityNamespace !== null) {
×
UNCOV
128
            $baseNamespace = $this->baseEntityNamespace . '\\';
×
UNCOV
129
            $length = strlen($baseNamespace);
×
130

UNCOV
131
            if (substr($entityClass, 0, $length) !== $baseNamespace) {
×
132
                throw new LogicException(sprintf('%s is not in namespace %s.', $entityClass, $this->baseEntityNamespace));
×
133
            }
134

UNCOV
135
            $entityClass = substr($entityClass, $length);
×
136
        }
137

UNCOV
138
        return $this->getProxyNamespace() . '\\' . $entityClass . 'Proxy';
×
139
    }
140

141
    public function getProxyFileName(string $entityClass): string
142
    {
143
        if ($this->baseEntityNamespace !== null) {
×
UNCOV
144
            $baseNamespace = $this->baseEntityNamespace . '\\';
×
UNCOV
145
            $length = strlen($baseNamespace);
×
146

UNCOV
147
            if (substr($entityClass, 0, $length) !== $baseNamespace) {
×
148
                throw new LogicException(sprintf('%s is not in namespace %s.', $entityClass, $this->baseEntityNamespace));
×
149
            }
150

UNCOV
151
            $entityClass = substr($entityClass, $length);
×
152
        }
153

UNCOV
154
        return $this->getProxyDir() . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $entityClass) . 'Proxy.php';
×
155
    }
156

157
    public function setProxyDir(string $proxyDir): Configuration
158
    {
159
        $this->proxyDir = $proxyDir;
×
160

UNCOV
161
        return $this;
×
162
    }
163

164
    /**
165
     * @throws LogicException
166
     */
167
    public function getProxyDir(): string
168
    {
UNCOV
169
        if ($this->proxyDir === null) {
×
UNCOV
170
            throw new LogicException('Proxy dir is not set.');
×
171
        }
172

UNCOV
173
        return $this->proxyDir;
×
174
    }
175

176
    public function setRepositoryNamespace(string $repositoryNamespace): Configuration
177
    {
178
        $this->repositoryNamespace = $repositoryNamespace;
×
179

UNCOV
180
        return $this;
×
181
    }
182

183
    /**
184
     * @throws LogicException
185
     */
186
    public function getRepositoryNamespace(?string $entityClass = null): string
187
    {
UNCOV
188
        if ($this->repositoryNamespace === null) {
×
UNCOV
189
            throw new LogicException('Repository namespace is not set.');
×
190
        }
191

UNCOV
192
        if ($entityClass === null) {
×
193
            return $this->repositoryNamespace;
×
194
        }
195

UNCOV
196
        if ($this->baseEntityNamespace !== null) {
×
197
            $baseNamespace = $this->baseEntityNamespace . '\\';
×
198
            $length = strlen($baseNamespace);
×
199

UNCOV
200
            if (substr($entityClass, 0, $length) !== $baseNamespace) {
×
201
                throw new LogicException(sprintf('%s is not in namespace %s.', $entityClass, $this->baseEntityNamespace));
×
202
            }
203

UNCOV
204
            $entityClass = substr($entityClass, $length);
×
205
        }
206

UNCOV
207
        $pos = strrpos($entityClass, '\\');
×
208

209
        if ($pos === false) {
×
UNCOV
210
            return $this->repositoryNamespace;
×
211
        }
212

UNCOV
213
        return $this->repositoryNamespace . '\\' . substr($entityClass, 0, $pos);
×
214
    }
215

216
    public function getRepositoryFileName(string $entityClass): string
217
    {
218
        if ($this->baseEntityNamespace !== null) {
×
UNCOV
219
            $baseNamespace = $this->baseEntityNamespace . '\\';
×
UNCOV
220
            $length = strlen($baseNamespace);
×
221

UNCOV
222
            if (substr($entityClass, 0, $length) !== $baseNamespace) {
×
223
                throw new LogicException(sprintf('%s is not in namespace %s.', $entityClass, $this->baseEntityNamespace));
×
224
            }
225

UNCOV
226
            $entityClass = substr($entityClass, $length);
×
227
        }
228

UNCOV
229
        return $this->getRepositoryDir() . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $entityClass) . 'Repository.php';
×
230
    }
231

232
    public function setRepositoryDir(string $repositoryDir): Configuration
233
    {
234
        $this->repositoryDir = $repositoryDir;
×
235

UNCOV
236
        return $this;
×
237
    }
238

239
    /**
240
     * @throws LogicException
241
     */
242
    public function getRepositoryDir(): string
243
    {
UNCOV
244
        if ($this->repositoryDir === null) {
×
UNCOV
245
            throw new LogicException('Repository dir is not set.');
×
246
        }
247

UNCOV
248
        return $this->repositoryDir;
×
249
    }
250

251
    /**
252
     * Sets the path to the PHP file where the ClassMetadata will be stored.
253
     */
254
    public function setClassMetadataFile(string $classMetadataFile): Configuration
255
    {
UNCOV
256
        if (substr($classMetadataFile, -4) !== '.php') {
×
UNCOV
257
            throw new InvalidArgumentException('The ClassMetadata file path must have a .php extension.');
×
258
        }
259

UNCOV
260
        $this->classMetadataFile = $classMetadataFile;
×
261

262
        return $this;
×
263
    }
264

265
    /**
266
     * @throws LogicException
267
     */
268
    public function getClassMetadataFile(): string
269
    {
UNCOV
270
        if ($this->classMetadataFile === null) {
×
UNCOV
271
            throw new LogicException('ClassMetadata file path is not set.');
×
272
        }
273

UNCOV
274
        return $this->classMetadataFile;
×
275
    }
276

277
    /**
278
     * Sets the base namespace all entities live in.
279
     *
280
     * This is optional, but restricts the number of sub-namespaces (and subdirs) created for repositories and proxies.
281
     *
282
     * For example, by default App\Model\User's repository would live in RepositoryNamespace\App\Model\UserRepository,
283
     * while with a base entity namespace of App\Model it would live in RepositoryNamespace\UserRepository.
284
     */
285
    public function setBaseEntityNamespace(string $namespace): Configuration
286
    {
UNCOV
287
        $this->baseEntityNamespace = $namespace;
×
288

UNCOV
289
        return $this;
×
290
    }
291

292
    public function getBaseEntityNamespace(): ?string
293
    {
294
        return $this->baseEntityNamespace;
×
295
    }
296

297
    /**
298
     * @param class-string $className
299
     */
300
    public function addEntity(string $className): EntityConfiguration
301
    {
UNCOV
302
        $entityConfiguration = new EntityConfiguration($this, $className);
×
UNCOV
303
        $this->classes[$className] = $entityConfiguration;
×
304

UNCOV
305
        return $entityConfiguration;
×
306
    }
307

308
    /**
309
     * @param class-string $className
310
     */
311
    public function addEmbeddable(string $className): EmbeddableConfiguration
312
    {
UNCOV
313
        $embeddableConfiguration = new EmbeddableConfiguration($this, $className);
×
UNCOV
314
        $this->classes[$className] = $embeddableConfiguration;
×
315

UNCOV
316
        return $embeddableConfiguration;
×
317
    }
318

319
    /**
320
     * Adds a custom mapping that applies by default to all properties of the given type.
321
     *
322
     * @param class-string                  $className       The mapped class name.
323
     * @param class-string<PropertyMapping> $propertyMapping The PropertyMapping implementation class name.
324
     */
325
    public function addCustomMapping(string $className, string $propertyMapping): Configuration
326
    {
UNCOV
327
        $this->customMappings[$className] = $propertyMapping;
×
328

UNCOV
329
        return $this;
×
330
    }
331

332
    /**
333
     * @return array<string, class-string<PropertyMapping>>
334
     */
335
    public function getCustomMappings(): array
336
    {
337
        return $this->customMappings;
×
338
    }
339

340
    /**
341
     * Adds a custom property mapping for a specific property of a given entity/embeddable class.
342
     *
343
     * @todo Naming of addCustomMapping() / setCustomPropertyMapping() is a bit confusing
344
     *
345
     * @param class-string $class
346
     */
347
    public function setCustomPropertyMapping(string $class, string $property, PropertyMapping $mapping): Configuration
348
    {
UNCOV
349
        $this->customPropertyMappings[$class][$property] = $mapping;
×
350

UNCOV
351
        return $this;
×
352
    }
353

354
    /**
355
     * @return array<class-string, array<string, PropertyMapping>>
356
     */
357
    public function getCustomPropertyMappings(): array
358
    {
359
        return $this->customPropertyMappings;
×
360
    }
361

362
    /**
363
     * @param class-string $class
364
     */
365
    public function setTransientProperties(string $class, string ...$properties): Configuration
366
    {
UNCOV
367
        $this->transientProperties[$class] = array_values($properties);
×
368

369
        return $this;
×
370
    }
371

372
    /**
373
     * Returns the list of transient properties for the given class name.
374
     *
375
     * @param class-string $class
376
     *
377
     * @return list<string>
378
     */
379
    public function getTransientProperties(string $class): array
380
    {
UNCOV
381
        return $this->transientProperties[$class] ?? [];
×
382
    }
383

384
    /**
385
     * @param class-string $class
386
     */
387
    public function setFieldName(string $class, string $property, string $fieldName): Configuration
388
    {
UNCOV
389
        $this->fieldNames[$class][$property] = $fieldName;
×
390

UNCOV
391
        return $this;
×
392
    }
393

394
    /**
395
     * Sets custom field names for builtin type properties.
396
     *
397
     * If not set, the field name defaults to the property name.
398
     *
399
     * @return array<class-string, array<string, string>>
400
     */
401
    public function getFieldNames(): array
402
    {
403
        return $this->fieldNames;
×
404
    }
405

406
    /**
407
     * Sets field name prefixes for entity/embeddable properties.
408
     *
409
     * If not set, the field name prefix defaults to the property name followed by an underscore character.
410
     *
411
     * @param class-string $class
412
     */
413
    public function setFieldNamePrefix(string $class, string $property, string $fieldNamePrefix): Configuration
414
    {
UNCOV
415
        $this->fieldNamePrefixes[$class][$property] = $fieldNamePrefix;
×
416

417
        return $this;
×
418
    }
419

420
    /**
421
     * @return array<class-string, array<string, string>>
422
     */
423
    public function getFieldNamePrefixes(): array
424
    {
UNCOV
425
        return $this->fieldNamePrefixes;
×
426
    }
427

428
    /**
429
     * Returns the class configurations, indexed by FQCN.
430
     *
431
     * @return array<class-string, ClassConfiguration>
432
     */
433
    public function getClasses(): array
434
    {
UNCOV
435
        return $this->classes;
×
436
    }
437

438
    /**
439
     * Returns the entity configurations, indexed by FQCN.
440
     *
441
     * @return array<class-string, EntityConfiguration>
442
     */
443
    public function getEntities(): array
444
    {
UNCOV
445
        $entityConfigurations = [];
×
446

UNCOV
447
        foreach ($this->classes as $className => $classConfiguration) {
×
UNCOV
448
            if ($classConfiguration instanceof EntityConfiguration) {
×
UNCOV
449
                $entityConfigurations[$className] = $classConfiguration;
×
450
            }
451
        }
452

453
        return $entityConfigurations;
×
454
    }
455
}
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