GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Push — master ( 316d38...a6fddc )
by SignpostMarv
02:47
created

PropertyReflectionExtension::SetSetterProps()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 2
dl 0
loc 17
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject\PHPStan;
10
11
use BadMethodCallException;
12
use InvalidArgumentException;
13
use PHPStan\Broker\Broker;
14
use PHPStan\Reflection\ClassReflection;
15
use PHPStan\Reflection\PropertyReflection;
16
use PHPStan\Type\MixedType;
17
use PHPStan\Type\Type;
18
use PHPStan\Type\TypehintHelper;
19
use ReflectionMethod;
20
use SignpostMarv\DaftObject\DaftObject;
21
use SignpostMarv\DaftObject\DefinesOwnIdPropertiesInterface;
22
use SignpostMarv\DaftObject\TypeUtilities;
23
24
class PropertyReflectionExtension implements PropertyReflection
25
{
26
    const REF_PARAM_INDEX = 0;
27
28
    const BOOL_IS_WRITEABLE = true;
29
30
    const BOOL_IS_READABLE = true;
31
32
    const BOOL_SETNOTGET_SETTER = true;
33
34
    const BOOL_SETNOTGET_GETTER = false;
35
36
    const BOOL_CLASS_NOT_DAFTOBJECT = false;
37
38
    const BOOL_REFLECTION_NO_FILE = false;
39
40
    const BOOL_NOT_VARIADIC = false;
41
42
    const BOOL_IS_STATIC = false;
43
44
    /**
45
    * @var Type
46
    */
47
    protected $type;
48
49
    /**
50
    * @var Broker
51
    */
52
    protected $broker;
53
54
    /**
55
    * @var bool
56
    */
57
    protected $readable = false;
58
59
    /**
60
    * @var bool
61
    */
62
    protected $writeable = false;
63
64
    /**
65
    * @var bool
66
    */
67
    protected $public;
68
69
    /**
70
    * @var ClassReflection|null
71
    */
72
    protected $readableReflection;
73
74
    /**
75
    * @var ClassReflection|null
76
    */
77
    protected $writeableReflection;
78
79
    public function __construct(ClassReflection $classReflection, Broker $broker, string $property)
80
    {
81
        if ( ! TypeUtilities::IsThingStrings($classReflection->getName(), DaftObject::class)) {
82
            throw new InvalidArgumentException(sprintf('%s is not an implementation of %s',
83
                $classReflection->getName(),
84
                DaftObject::class
85
            ));
86
        }
87
88
        $this->broker = $broker;
89
90
        $this->public = static::PropertyIsPublic($classReflection->getName(), $property);
91
92
        $this->type = new MixedType();
93
94
        $this->SetupReflections($classReflection, $property);
95
    }
96
97
    public function getType() : Type
98
    {
99
        return $this->type;
100
    }
101
102
    public function isReadable() : bool
103
    {
104
        return $this->readable;
105
    }
106
107
    public function isWritable() : bool
108
    {
109
        return $this->writeable;
110
    }
111
112
    public function isPublic() : bool
113
    {
114
        return $this->public;
115
    }
116
117
    public function isPrivate() : bool
118
    {
119
        return ! $this->isPublic();
120
    }
121
122
    public function isStatic() : bool
123
    {
124
        return self::BOOL_IS_STATIC;
125
    }
126
127
    public function getDeclaringClass() : ClassReflection
128
    {
129
        $reflection = $this->readable ? $this->readableReflection : $this->writeableReflection;
130
131
        if ( ! ($reflection instanceof ClassReflection)) {
132
            throw new BadMethodCallException(
133
                static::class .
134
                '::SetupReflections() was not called before ' .
135
                __METHOD__ .
136
                ' was called!'
137
            );
138
        }
139
140
        return $reflection;
141
    }
142
143
    private function SetupReflections(ClassReflection $classReflection, string $property) : void
144
    {
145
        $class = $classReflection->getName();
146
        $get = TypeUtilities::MethodNameFromProperty($property, self::BOOL_SETNOTGET_GETTER);
147
        $set = TypeUtilities::MethodNameFromProperty($property, self::BOOL_SETNOTGET_SETTER);
148
149
        $this->writeableReflection = $this->readableReflection = $classReflection;
150
151
        if ($classReflection->getNativeReflection()->hasMethod($get)) {
152
            $this->readableReflection = $this->SetGetterProps(new ReflectionMethod($class, $get));
153
        }
154
155
        if ($classReflection->getNativeReflection()->hasMethod($set)) {
156
            $this->writeableReflection = $this->SetSetterProps($class, $set);
157
        }
158
    }
159
160
    private function SetGetterProps(ReflectionMethod $refMethod) : ClassReflection
161
    {
162
        $this->readable = self::BOOL_IS_READABLE;
163
164
        if ($refMethod->isStatic()) {
165
            throw new InvalidArgumentException(
166
                'Implementations of ' .
167
                DaftObject::class .
168
                ' must not contain static getters.'
169
            );
170
        }
171
172
        if ($refMethod->hasReturnType()) {
173
            $this->type = TypehintHelper::decideTypeFromReflection($refMethod->getReturnType());
174
        }
175
176
        return static::DetermineDeclaringClass($this->broker, $refMethod);
177
    }
178
179
    private function SetSetterProps(string $class, string $set) : ClassReflection
180
    {
181
        $refMethod = new ReflectionMethod($class, $set);
182
        $this->writeable = self::BOOL_IS_WRITEABLE;
183
184
        $refParam = $refMethod->getParameters()[self::REF_PARAM_INDEX];
185
186
        if ($refParam->hasType()) {
187
            $this->type = TypehintHelper::decideTypeFromReflection(
188
                $refParam->getType(),
189
                null,
190
                $class,
191
                self::BOOL_NOT_VARIADIC
192
            );
193
        }
194
195
        return static::DetermineDeclaringClass($this->broker, $refMethod);
196
    }
197
198
    private static function DetermineDeclaringClass(
199
        Broker $broker,
200
        ReflectionMethod $refMethod
201
    ) : ClassReflection {
202
        $reflectionClass = $refMethod->getDeclaringClass();
203
204
        $filename = null;
205
        if (self::BOOL_REFLECTION_NO_FILE !== $reflectionClass->getFileName()) {
206
            $filename = $reflectionClass->getFileName();
207
        }
208
209
        return $broker->getClassFromReflection(
210
            $reflectionClass,
211
            $reflectionClass->getName(),
212
            $reflectionClass->isAnonymous() ? $filename : null
213
        );
214
    }
215
216
    /**
217
    * @psalm-suppress InvalidStringClass
218
    * @psalm-suppress MixedMethodCall
219
    */
220
    private static function PropertyIsPublic(string $className, string $property) : bool
221
    {
222
        if ( ! TypeUtilities::IsSubThingStrings($className, DaftObject::class)) {
223
            return self::BOOL_CLASS_NOT_DAFTOBJECT;
224
        }
225
226
        return
227
            (
228
                TypeUtilities::IsThingStrings(
229
                    $className,
230
                    DefinesOwnIdPropertiesInterface::class
231
                ) &&
232
                'id' === $property
233
            ) ||
234
            TypeUtilities::MaybeInMaybeArray($property, $className::DaftObjectPublicGetters()) ||
235
            TypeUtilities::MaybeInMaybeArray($property, $className::DaftObjectPublicSetters());
236
    }
237
}
238