Completed
Pull Request — master (#423)
by Marco
07:12
created

Properties::withoutNonReferenceableProperties()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 8
cp 0
rs 9.7
c 0
b 0
f 0
cc 3
nc 1
nop 0
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProxyManager\ProxyGenerator\Util;
6
7
use ReflectionClass;
8
use ReflectionProperty;
9
10
/**
11
 * DTO containing the list of all non-static proxy properties and utility methods to access them
12
 * in various formats/collections
13
 *
14
 * @author Marco Pivetta <[email protected]>
15
 * @license MIT
16
 */
17
final class Properties
18
{
19
    /**
20
     * @var array|\ReflectionProperty[]
21
     */
22
    private $properties;
23
24
    /**
25
     * @param ReflectionProperty[] $properties
26
     */
27 15
    private function __construct(array $properties)
28
    {
29 15
        $this->properties = $properties;
30 15
    }
31
32 15
    public static function fromReflectionClass(ReflectionClass $reflection) : self
33
    {
34 15
        $class      = $reflection;
35 15
        $properties = [];
36
37
        do {
38 15
            $properties = array_merge(
39 15
                $properties,
40 15
                array_values(array_filter(
41 15
                    $class->getProperties(),
42
                    function (ReflectionProperty $property) use ($class) : bool {
43 13
                        return $class->getName() === $property->getDeclaringClass()->getName()
44 13
                            && ! $property->isStatic();
45 15
                    }
46
                ))
47
            );
48 15
        } while ($class = $class->getParentClass());
49
50 15
        return new self($properties);
51
    }
52
53
    /**
54
     * @param string[] $excludedProperties
55
     */
56 5
    public function filter(array $excludedProperties) : self
57
    {
58 5
        $properties = $this->getInstanceProperties();
59
60 5
        foreach ($excludedProperties as $propertyName) {
61 5
            unset($properties[$propertyName]);
62
        }
63
64 5
        return new self($properties);
65
    }
66
67
    /**
68
     * Properties that cannot be referenced are non-nullable typed properties that aren't initialised
69
     */
70
    public function withoutNonReferenceableProperties() : self
71
    {
72
        return new self(array_filter($this->getInstanceProperties(), function (ReflectionProperty $property) : bool {
73
            if (! $property->hasType()) {
74
                return true;
75
            }
76
77
            /** @var $type \ReflectionType */
78
            $type = $property->getType();
79
80
            if ($type->allowsNull()) {
81
                return true;
82
            }
83
84
            return isset($property->getDeclaringClass()->getDefaultProperties()[$property->getName()]);
85
        }));
86
    }
87
88
    /**
89
     * @return ReflectionProperty[] indexed by the property internal visibility-aware name
90
     */
91 9
    public function getPublicProperties() : array
92
    {
93 9
        $publicProperties = [];
94
95 9
        foreach ($this->properties as $property) {
96 8
            if ($property->isPublic()) {
97 8
                $publicProperties[$property->getName()] = $property;
98
            }
99
        }
100
101 9
        return $publicProperties;
102
    }
103
104
    /**
105
     * @return ReflectionProperty[] indexed by the property internal visibility-aware name (\0*\0propertyName)
106
     */
107 9
    public function getProtectedProperties() : array
108
    {
109 9
        $protectedProperties = [];
110
111 9
        foreach ($this->properties as $property) {
112 8
            if ($property->isProtected()) {
113 8
                $protectedProperties["\0*\0" . $property->getName()] = $property;
114
            }
115
        }
116
117 9
        return $protectedProperties;
118
    }
119
120
    /**
121
     * @return ReflectionProperty[] indexed by the property internal visibility-aware name (\0ClassName\0propertyName)
122
     */
123 10
    public function getPrivateProperties() : array
124
    {
125 10
        $privateProperties = [];
126
127 10
        foreach ($this->properties as $property) {
128 10
            if ($property->isPrivate()) {
129 10
                $declaringClass = $property->getDeclaringClass()->getName();
130
131 10
                $privateProperties["\0" . $declaringClass . "\0" . $property->getName()] = $property;
132
            }
133
        }
134
135 10
        return $privateProperties;
136
    }
137
138
    /**
139
     * @return ReflectionProperty[] indexed by the property internal visibility-aware name (\0*\0propertyName)
140
     */
141 7
    public function getAccessibleProperties() : array
142
    {
143 7
        return array_merge($this->getPublicProperties(), $this->getProtectedProperties());
144
    }
145
146
    /**
147
     * @return ReflectionProperty[][] indexed by class name and property name
148
     */
149 2
    public function getGroupedPrivateProperties() : array
150
    {
151 2
        $propertiesMap = [];
152
153 2
        foreach ($this->getPrivateProperties() as $property) {
154 2
            $class = & $propertiesMap[$property->getDeclaringClass()->getName()];
155
156 2
            $class[$property->getName()] = $property;
157
        }
158
159 2
        return $propertiesMap;
160
    }
161
162
    /**
163
     * @return ReflectionProperty[] indexed by the property internal visibility-aware name (\0*\0propertyName)
164
     */
165 6
    public function getInstanceProperties() : array
166
    {
167 6
        return array_merge($this->getAccessibleProperties(), $this->getPrivateProperties());
168
    }
169
}
170