Passed
Push — master ( fd52a1...f10307 )
by JHONATAN
04:12
created

PropertyMetadata::getValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
crap 2
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 54
    public function __construct($class, $name)
27
    {
28 54
        parent::__construct($class, $name);
29
        
30 54
        $this->type     = $this->parseType();
31 54
        $this->typeInfo = $this->parseTypeDecoration($this->type);
32 54
    }
33
    
34 28
    public function getValue($obj)
35
    {
36 28
        if ($obj instanceof AccessInterceptorValueHolderInterface) {
37 10
            $obj = $obj->getWrappedValueHolderValue();
38
        }
39
        
40 28
        return parent::getValue($obj);
41
    }
42
    
43 30
    public function setValue($obj, $value)
44
    {
45 30
        if ($obj instanceof AccessInterceptorValueHolderInterface) {
46 3
            $obj = $obj->getWrappedValueHolderValue();
47
        }
48
        
49 30
        parent::setValue($obj, $value);
50 30
    }
51
    
52 54
    private function parseType()
53
    {
54 54
        $docComment = $this->reflection->getDocComment();
55
        
56 54
        preg_match('/@var\s+(([^\[\]\s]+)(\[\])?)/', $docComment, $matches);
57
        
58 54
        $fullType = $matches[1] ?? null;
59 54
        $type     = $matches[2] ?? null;
60
        
61 54
        if (null === $type) {
62 24
            return;
63
        }
64
        
65 42
        $uses = $this->getClassUses();
66
        
67 42
        foreach ($uses as $use) {
68 42
            if (preg_match("/{$type}$/", $use)) {
69 1
                return $use . ($matches[3] ?? null);
70
            }
71
            
72 42
            if (class_exists("$use\\$type")) {
73 42
                return "$use\\$type" . ($matches[3] ?? null);
74
            }
75
        }
76
        
77 40
        return $fullType;
78
    }
79
    
80 42
    private function getClassUses(): array
81
    {
82 42
        $filename = $this->reflection->getDeclaringClass()->getFileName();
83
        
84 42
        if (is_file($filename)) {
85 42
            $contents = file_get_contents($filename);
86
            
87 42
            preg_match_all('/use\s+(.*);/', $contents, $matches);
88
            
89 42
            $uses = $matches[1] ?? [];
90
            
91 42
            $matches = [];
92
            
93 42
            preg_match('/namespace\s+(.*);/', $contents, $matches);
94
            
95 42
            if (!empty($matches[1])) {
96 42
                array_push($uses, $matches[1]);
97
            }
98
            
99 42
            return $uses;
100
        }
101
        
102
        return [];
103
    }
104
    
105 9
    public function getParsedType()
106
    {
107 9
        if (isset($this->type)) {
108 9
            return preg_replace('/(\[\]$)|(\<\>$)/', '', $this->type);
109
        }
110 2
    }
111
    
112 15
    public function isNativeType(): bool
113
    {
114 15
        return in_array($this->type, [
115 15
            '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 21
    public function isDecoratedType(): bool
130
    {
131 21
        return (bool) preg_match('/(.*)((\<(.*)\>)|(\[\]))/', $this->type);
132
    }
133
    
134 9
    public function isDateType(): bool
135
    {
136 9
        $type = $this->isDecoratedType() ? $this->typeInfo['class'] ?? $this->type : $this->type;
137
        
138 9
        return in_array($type, ['DateTime', '\DateTime', 'DateTimeImmutable', '\DateTimeImmutable']);
139
    }
140
    
141 54
    private function parseTypeDecoration(string $type = null)
142
    {
143 54
        if (preg_match('/(?P<class>.*)((\<(?P<decoration>.*)\>)|(?P<brackets>\[\]))/', $type, $matches)) {
144
            return [
145 14
                'class'      => isset($matches['brackets']) ? 'array' : $matches['class'],
146 14
                'decoration' => isset($matches['brackets']) ? $matches['class'] : $matches['decoration']
147
            ];
148
        }
149 53
    }
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