• 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/RepositoryBuilder.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\ORM;
6

7
use ReflectionClass;
8
use ReflectionException;
9
use RuntimeException;
10

11
use function array_unique;
12
use function array_values;
13
use function count;
14
use function file_get_contents;
15
use function implode;
16
use function in_array;
17
use function ord;
18
use function str_replace;
19
use function strlen;
20
use function strtolower;
21
use function substr;
22
use function var_export;
23

24
class RepositoryBuilder
25
{
26
    private ?string $repositoryNamespace = null;
27

28
    /**
29
     * @var class-string|null
30
     */
31
    private ?string $entityClassName = null;
32

33
    /**
34
     * @var array<string, string>|null
35
     */
36
    private ?array $identityProps = null;
37

38
    /**
39
     * @param string $namespace The namespace of the repository.
40
     */
41
    public function setRepositoryNamespace(string $namespace): void
42
    {
UNCOV
43
        $this->repositoryNamespace = $namespace;
×
44
    }
45

46
    /**
47
     * @param class-string $className The FQCN of the entity.
48
     */
49
    public function setEntityClassName(string $className): void
50
    {
UNCOV
51
        $this->entityClassName = $className;
×
52
    }
53

54
    /**
55
     * @param array<string, string> $props An associative array of property name to type.
56
     */
57
    public function setIdentityProps(array $props): void
58
    {
UNCOV
59
        $this->identityProps = $props;
×
60
    }
61

62
    /**
63
     * Builds and returns the repository source code.
64
     *
65
     * @throws RuntimeException    If data are missing.
66
     * @throws ReflectionException If a class does not exist.
67
     */
68
    public function build(): string
69
    {
70
        if ($this->repositoryNamespace === null) {
×
71
            throw new RuntimeException('Missing repository namespace.');
×
72
        }
73

UNCOV
74
        if ($this->entityClassName === null) {
×
75
            throw new RuntimeException('Missing entity class name.');
×
76
        }
77

78
        if ($this->identityProps === null) {
×
79
            throw new RuntimeException('Missing identity props.');
×
80
        }
81

UNCOV
82
        $imports = [
×
83
            $this->entityClassName,
×
84
        ];
×
85

86
        $entityClassShortName = (new ReflectionClass($this->entityClassName))->getShortName();
×
87

88
        $code = file_get_contents(__DIR__ . '/RepositoryTemplate.php');
×
89

90
        $code = str_replace('REPO_NAMESPACE', $this->repositoryNamespace, $code);
×
91
        $code = str_replace('CLASS_NAME', $entityClassShortName, $code);
×
92
        $code = str_replace('ENTITY_PROP_NAME', $this->getParamNameForClassName($entityClassShortName), $code);
×
93

94
        // Identity props & array
95

UNCOV
96
        $builtInTypes = [
×
97
            'bool',
×
98
            'int',
×
UNCOV
99
            'float',
×
100
            'string',
×
101
            'array',
×
UNCOV
102
            'object',
×
UNCOV
103
            'callable',
×
104
            'iterable',
×
105
        ];
×
106

UNCOV
107
        $identityProps = [];
×
108
        $identityArray = [];
×
109

UNCOV
110
        foreach ($this->identityProps as $prop => $type) {
×
UNCOV
111
            $typeLower = strtolower($type);
×
112

113
            if (in_array($typeLower, $builtInTypes, true)) {
×
UNCOV
114
                $type = $typeLower;
×
115
            } else {
116
                /** @var class-string $type */
117
                $imports[] = $type;
×
UNCOV
118
                $type = (new ReflectionClass($type))->getShortName();
×
119
            }
120

121
            $identityProps[] = $type . ' $' . $prop;
×
122
            $identityArray[] = var_export($prop, true) . ' => $' . $prop;
×
123
        }
124

UNCOV
125
        $code = str_replace('$IDENTITY_PROPS', implode(', ', $identityProps), $code);
×
126
        $code = str_replace('IDENTITY_ARRAY', '[' . implode(', ', $identityArray) . ']', $code);
×
127

128
        // Imports
129

UNCOV
130
        $importString = '';
×
131

UNCOV
132
        $imports = array_values(array_unique($imports));
×
133

UNCOV
134
        foreach ($imports as $key => $import) {
×
135
            if ($key !== 0) {
×
UNCOV
136
                $importString .= '    ';
×
137
            }
138

UNCOV
139
            $importString .= $import;
×
140

UNCOV
141
            if ($key !== count($imports) - 1) {
×
UNCOV
142
                $importString .= ",\n";
×
143
            }
144
        }
145

UNCOV
146
        $code = str_replace('IMPORTS', $importString, $code);
×
147

UNCOV
148
        return $code;
×
149
    }
150

151
    /**
152
     * Returns a suitable parameter name for a class name.
153
     *
154
     * Examples: 'User' => 'user', 'ABBREntity' => 'abbrEntity'.
155
     */
156
    private function getParamNameForClassName(string $className): string
157
    {
158
        $length = strlen($className);
×
159

UNCOV
160
        $upperLength = 0;
×
161

162
        for ($i = 0; $i < $length; $i++) {
×
UNCOV
163
            if ($this->isUppercase($className[$i])) {
×
UNCOV
164
                $upperLength++;
×
165
            } else {
UNCOV
166
                break;
×
167
            }
168
        }
169

UNCOV
170
        if ($upperLength === 0) {
×
UNCOV
171
            return $className;
×
172
        }
173

UNCOV
174
        if ($upperLength > 1) {
×
175
            $upperLength--;
×
176
        }
177

UNCOV
178
        return strtolower(substr($className, 0, $upperLength)) . substr($className, $upperLength);
×
179
    }
180

181
    /**
182
     * Checks if an ASCII letter is uppercase.
183
     */
184
    private function isUppercase(string $letter): bool
185
    {
UNCOV
186
        $ord = ord($letter);
×
187

UNCOV
188
        return ($ord >= 65) && ($ord <= 90);
×
189
    }
190
}
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