PropertyMetadata::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Vox\Metadata;
4
5
use Metadata\PropertyMetadata as BaseMetadata;
6
use ProxyManager\Proxy\AccessInterceptorValueHolderInterface;
7
use ReflectionClass;
8
9
/**
10
 * Holds all metadata for a single property
11
 * 
12
 * @author Jhonatan Teixeira <[email protected]>
13
 */
14
class PropertyMetadata extends BaseMetadata
15
{
16
    use AnnotationsTrait;
17
    
18
    public $type;
19
    
20
    public $typeInfo;
21
    
22
    /**
23
     * @param ReflectionClass $class
24
     * @param string $name
25
     */
26 65
    public function __construct($class, $name)
27
    {
28 65
        parent::__construct($class, $name);
29
        
30 65
        $this->type     = $this->parseType();
31 65
        $this->typeInfo = $this->parseTypeDecoration($this->type);
32 65
    }
33
    
34 39
    public function getValue($obj)
35
    {
36 39
        if ($obj instanceof AccessInterceptorValueHolderInterface) {
37 17
            $obj = $obj->getWrappedValueHolderValue();
38
        }
39
        
40 39
        return parent::getValue($obj);
41
    }
42
    
43 36
    public function setValue($obj, $value)
44
    {
45 36
        if ($obj instanceof AccessInterceptorValueHolderInterface) {
46 5
            $obj = $obj->getWrappedValueHolderValue();
47
        }
48
        
49 36
        parent::setValue($obj, $value);
50 36
    }
51
    
52 65
    private function parseType()
53
    {
54 65
        $docComment = $this->reflection->getDocComment();
55
        
56 65
        preg_match('/@var\s+(([^\[\]' . PHP_EOL . ']+)(\[\])?)/', $docComment, $matches);
57
        
58 65
        $fullType = $matches[1] ?? null;
59 65
        $type     = $matches[2] ?? null;
60
        
61 65
        if (null === $type) {
62 28
            return;
63
        }
64
        
65 53
        $uses = $this->getClassUses();
66
        
67 53
        foreach ($uses as $use) {
68 53
            if (preg_match("/{$type}$/", $use)) {
69 1
                return $use . ($matches[3] ?? null);
70
            }
71
            
72 53
            if (class_exists("$use\\$type")) {
73 53
                return "$use\\$type" . ($matches[3] ?? null);
74
            }
75
        }
76
        
77 51
        return $fullType;
78
    }
79
    
80 53
    private function getClassUses(): array
81
    {
82 53
        $filename = $this->reflection->getDeclaringClass()->getFileName();
83
        
84 53
        if (is_file($filename)) {
85 53
            $contents = file_get_contents($filename);
86
            
87 53
            preg_match_all('/use\s+(.*);/', $contents, $matches);
88
            
89 53
            $uses = $matches[1] ?? [];
90
            
91 53
            $matches = [];
92
            
93 53
            preg_match('/namespace\s+(.*);/', $contents, $matches);
94
            
95 53
            if (!empty($matches[1])) {
96 53
                array_push($uses, $matches[1]);
97
            }
98
            
99 53
            return $uses;
100
        }
101
        
102
        return [];
103
    }
104
    
105 14
    public function getParsedType()
106
    {
107 14
        if (isset($this->type)) {
108 14
            return preg_replace('/(\[\]$)|(\<\>$)/', '', $this->type);
109
        }
110 2
    }
111
    
112 21
    public function isNativeType(): bool
113
    {
114 21
        return in_array($this->type, [
115 21
            'string',
116
            'array',
117
            'int',
118
            'integer',
119
            'float',
120
            'boolean',
121
            'bool',
122
            'DateTime',
123
            '\DateTime',
124
            '\DateTimeImmutable',
125
            'DateTimeImmutable',
126
        ]);
127
    }
128
    
129 29
    public function isDecoratedType(): bool
130
    {
131 29
        return (bool) preg_match('/(.*)((\<(.*)\>)|(\[\]))/', $this->type);
132
    }
133
    
134 14
    public function isDateType(): bool
135
    {
136 14
        $type = $this->isDecoratedType() ? $this->typeInfo['class'] ?? $this->type : $this->type;
137
        
138 14
        return in_array($type, ['DateTime', '\DateTime', 'DateTimeImmutable', '\DateTimeImmutable']);
139
    }
140
    
141 65
    private function parseTypeDecoration(string $type = null)
142
    {
143 65
        if (preg_match('/(?P<class>.*)((\<(?P<decoration>.*)\>)|(?P<brackets>\[\]))/', $type, $matches)) {
144
            return [
145 20
                'class'      => isset($matches['brackets']) ? 'array' : $matches['class'],
146 20
                'decoration' => isset($matches['brackets']) ? $matches['class'] : $matches['decoration']
147
            ];
148
        }
149 64
    }
150
    
151 6
    public function serialize()
152
    {
153 6
        return serialize([
154 6
            $this->class,
155 6
            $this->name,
156 6
            $this->annotations,
157 6
            $this->type,
158 6
            $this->typeInfo,
159
        ]);
160
    }
161
162 4
    public function unserialize($str)
163
    {
164 4
        list($this->class, $this->name, $this->annotations, $this->type, $this->typeInfo) = unserialize($str);
165
166 4
        $this->reflection = new \ReflectionProperty($this->class, $this->name);
167 4
        $this->reflection->setAccessible(true);
168 4
    }
169
}
170