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

3
declare(strict_types=1);
4

5
namespace Brick\ORM;
6

7
use InvalidArgumentException;
8
use LogicException;
9
use ReflectionClass;
10
use ReflectionException;
11
use ReflectionNamedType;
12
use ReflectionProperty;
13

14
use function count;
15
use function in_array;
16
use function sprintf;
17

18
abstract class ClassConfiguration
19
{
20
    protected Configuration $configuration;
21

22
    protected ReflectionClass $reflectionClass;
23

24
    /**
25
     * @param class-string $className
26
     *
27
     * @throws InvalidArgumentException
28
     */
29
    public function __construct(Configuration $configuration, string $className)
30
    {
UNCOV
31
        $this->configuration = $configuration;
×
32

33
        try {
UNCOV
34
            $this->reflectionClass = new ReflectionClass($className);
×
UNCOV
35
        } catch (ReflectionException $e) {
×
36
            throw new InvalidArgumentException(sprintf('%s does not exist.', $className), 0, $e);
×
37
        }
38
    }
39

40
    /**
41
     * @return class-string
42
     */
43
    public function getClassName(): string
44
    {
UNCOV
45
        return $this->reflectionClass->getName();
×
46
    }
47

48
    /**
49
     * @param class-string|null $className The entity class name, or null to use the root entity (this entity)'s class name.
50
     *
51
     * @return list<string>
52
     *
53
     * @throws LogicException
54
     */
55
    public function getPersistentProperties(?string $className = null): array
56
    {
UNCOV
57
        if ($className === null) {
×
58
            $reflectionClass = $this->reflectionClass;
×
59
        } else {
60
            $reflectionClass = new ReflectionClass($className);
×
61
        }
62

63
        $className = $reflectionClass->getName();
×
64

UNCOV
65
        $persistableProperties = [];
×
66

67
        foreach ($reflectionClass->getProperties() as $reflectionProperty) {
×
UNCOV
68
            if ($reflectionProperty->isStatic()) {
×
69
                continue;
×
70
            }
71

UNCOV
72
            $propertyName = $reflectionProperty->getName();
×
73

74
            if (in_array($propertyName, $this->configuration->getTransientProperties($className))) {
×
UNCOV
75
                continue;
×
76
            }
77

78
            if ($reflectionProperty->isPrivate()) {
×
UNCOV
79
                throw new LogicException(sprintf('%s::$%s is private; private properties are not supported. Make the property protected, or add it to transient properties if it should not be persistent.', $className, $propertyName));
×
80
            }
81

UNCOV
82
            if (! $reflectionProperty->hasType()) {
×
UNCOV
83
                throw new LogicException(sprintf('%s::$%s is not typed. Add a type to the property, or add it to transient properties if it should not be persistent.', $className, $propertyName));
×
84
            }
85

UNCOV
86
            $persistableProperties[] = $propertyName;
×
87
        }
88

UNCOV
89
        if (count($persistableProperties) === 0) {
×
UNCOV
90
            throw new LogicException(sprintf('%s has not persistable properties.', $className));
×
91
        }
92

UNCOV
93
        return $persistableProperties;
×
94
    }
95

96
    /**
97
     * @param class-string         $className          The entity class name.
98
     * @param string               $propertyName       The property name.
99
     * @param EntityMetadata[]     $entityMetadata     A map of FQCN to EntityMetadata instances.
100
     * @param EmbeddableMetadata[] $embeddableMetadata A map of FQCN to EmbeddableMetadata instances.
101
     *
102
     * @throws LogicException
103
     */
104
    public function getPropertyMapping(string $className, string $propertyName, array $entityMetadata, array $embeddableMetadata): PropertyMapping
105
    {
UNCOV
106
        if (! in_array($propertyName, $this->getPersistentProperties($className))) {
×
107
            throw new InvalidArgumentException(sprintf('Cannot return property mapping for unknown or non-persistent property %s::$%s.', $className, $propertyName));
×
108
        }
109

110
        $customPropertyMappings = $this->configuration->getCustomPropertyMappings();
×
111

UNCOV
112
        if (isset($customPropertyMappings[$className][$propertyName])) {
×
113
            return $customPropertyMappings[$className][$propertyName];
×
114
        }
115

UNCOV
116
        $reflectionProperty = new ReflectionProperty($className, $propertyName);
×
117

118
        $propertyType = $reflectionProperty->getType();
×
119

UNCOV
120
        if (! $propertyType instanceof ReflectionNamedType) {
×
121
            throw new LogicException('Property does not have a single type.');
×
122
        }
123

124
        $typeName = $propertyType->getName();
×
125
        $allowsNull = $propertyType->allowsNull();
×
126

127
        $fieldNames = $this->configuration->getFieldNames();
×
128
        $fieldName = $fieldNames[$className][$propertyName] ?? $propertyName;
×
129

130
        if ($propertyType->isBuiltin()) {
×
131
            return match ($typeName) {
×
132
                'int' => new PropertyMapping\IntMapping($fieldName, $allowsNull),
×
133
                'string' => new PropertyMapping\StringMapping($fieldName, $allowsNull),
×
134
                'bool' => new PropertyMapping\BoolMapping($fieldName, $allowsNull),
×
UNCOV
135
                'array' => throw new LogicException(sprintf('Cannot persist type "array" in %s::$%s; you can store an array as JSON if you wish, by configuring a custom JsonMapping instance.', $className, $propertyName)),
×
UNCOV
136
                default => throw new LogicException(sprintf('Cannot persist type "%s" in %s::$%s.', $typeName, $className, $propertyName))
×
137
            };
×
138
        }
139

UNCOV
140
        $customMappings = $this->configuration->getCustomMappings();
×
141

UNCOV
142
        if (isset($customMappings[$typeName])) {
×
143
            // @todo for now this only works with a single field name/prefix, and fixed constructor
144
            return new $customMappings[$typeName]($fieldName, $allowsNull);
×
145
        }
146

147
        $fieldNamePrefixes = $this->configuration->getFieldNamePrefixes();
×
148
        $fieldNamePrefix = $fieldNamePrefixes[$className][$propertyName] ?? $propertyName . '_';
×
149

UNCOV
150
        if (isset($entityMetadata[$typeName])) {
×
151
            return new PropertyMapping\EntityMapping($entityMetadata[$typeName], $fieldNamePrefix, $allowsNull);
×
152
        }
153

UNCOV
154
        if (isset($embeddableMetadata[$typeName])) {
×
155
            return new PropertyMapping\EmbeddableMapping($embeddableMetadata[$typeName], $fieldNamePrefix, $allowsNull);
×
156
        }
157

UNCOV
158
        throw new LogicException(sprintf('Type %s of %s::$%s is not an entity or embeddable, and has no custom mapping defined.', $typeName, $className, $propertyName));
×
159
    }
160
}
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