ClassParser::createClassField()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Mapper;
6
7
use \Reflection\ClassUseStatements as ReflectionClass;
8
use \ReflectionMethod;
9
10
/**
11
 * Class ClassParser
12
 * @package Mapper
13
 */
14
class ClassParser {
15
16
    /**
17
     * @const string
18
     */
19
    const PARAM_SETTER_PATTERN = '/@param\s+(.+)/';
20
21
    /**
22
     * @var string
23
     */
24
    private $class;
25
26
    /**
27
     * @var ReflectionClass
28
     */
29
    private $reflectionClass;
30
31
    /**
32
     * @param string $class
33
     */
34 6
    public function __construct(string $class) {
35 6
        $this->setClass($class);
36 6
    }
37
38
    /**
39
     * @return string
40
     */
41 1
    public function getClass() {
42 1
        return $this->class;
43
    }
44
45
    /**
46
     * @param string $class
47
     * @return ClassParser
48
     */
49 6
    public function setClass(string $class): ClassParser {
50 6
        $this->class = $class;
51
52 6
        return $this->setReflectionClass(new ReflectionClass($class));
53
    }
54
55
    /**
56
     * @return ReflectionClass
57
     */
58 4
    protected function getReflectionClass(): ReflectionClass {
59 4
        return $this->reflectionClass;
60
    }
61
62
    /**
63
     * @param ReflectionClass $reflectionClass
64
     * @return ClassParser
65
     */
66 6
    private function setReflectionClass(ReflectionClass $reflectionClass): ClassParser {
67 6
        $this->reflectionClass = $reflectionClass;
68
69 6
        return $this;
70
    }
71
72
    /**
73
     * @return ClassFields
74
     */
75 4
    public function getClassFields(): ClassFields {
76 4
        $methods = $this->getReflectionClass()
77 4
            ->getMethods();
78
79 4
        $classFields = new ClassFields();
80
81 4
        foreach ($methods as $method) {
82 4
            if ($this->isSetterMethod($method)) {
83 4
                $classFields->add($this->createClassField($method));
84
            }
85
        }
86
87 4
        return $classFields;
88
    }
89
90
    /**
91
     * @param ReflectionMethod $method
92
     * @return bool
93
     */
94 4
    private function isSetterMethod(ReflectionMethod $method): bool {
95 4
        return strpos($method->name, 'set') !== false;
96
    }
97
98
    /**
99
     * @param ReflectionMethod $method
100
     * @return ClassField
101
     */
102 4
    private function createClassField(ReflectionMethod $method): ClassField {
103 4
        $classField = new ClassField(
104 4
            $method->name,
105 4
            lcfirst(str_replace('set', '', $method->name))
106
        );
107
108 4
        $this->setupClassFieldFromAnnotation($classField, $method);
109
110 4
        if (empty($classField->getType())) {
111 4
            $this->setupClassFieldFromSignature($classField, $method);
112
        }
113
114 4
        return $classField;
115
    }
116
117
    /**
118
     * @param ClassField $classField
119
     * @param ReflectionMethod $method
120
     * @return ClassParser
121
     */
122 4
    private function setupClassFieldFromAnnotation(ClassField $classField, ReflectionMethod $method): ClassParser {
123 4
        preg_match(self::PARAM_SETTER_PATTERN, $method->getDocComment(), $paramTypeAndVariable);
124
125 4
        if (isset($paramTypeAndVariable[1])) {
126 4
            $types = preg_split(
127 4
                '/\s+/',
128 4
                $paramTypeAndVariable[1],
129 4
                $limit = 3,
130 4
                PREG_SPLIT_DELIM_CAPTURE
131
            );
132
133 4
            foreach ($types as $type) {
134 4
                if ($type[0] !== '$') {
135 4
                    if (strpos($type, '[]') !== false) {
136 4
                        $classField->setIsSequential();
137
138 4
                        $type = str_replace('[]', '', $type);
139
                    }
140
141 4
                    $this->setupClassFieldType($classField, $type);
142
143 4
                    break;
144
                }
145
            }
146
        }
147
148 4
        return $this;
149
    }
150
151
    /**
152
     * @param ClassField $classField
153
     * @param ReflectionMethod $method
154
     * @return ClassParser
155
     */
156 4
    private function setupClassFieldFromSignature(ClassField $classField, ReflectionMethod $method): ClassParser {
157 4
        $parameters = $method->getParameters();
158
159 4
        if (isset($parameters[0])) {
160 4
            $type = (string) $parameters[0]->getType();
161
162 4
            $classField->setType($type);
163
        }
164
165 4
        return $this;
166
    }
167
168
    /**
169
     * @param ClassField $classField
170
     * @param string $type
171
     * @return ClassParser
172
     */
173 4
    private function setupClassFieldType(ClassField $classField, string $type): ClassParser {
174 4
        if ($this->typeIsNotStandard($type)) {
175 4
            $fullClassName = $this->getReflectionClass()
176 4
                ->getUseStatements()
177 4
                ->getFullClassName($type);
178
179 4
            if ($fullClassName) {
180 4
                $type = $fullClassName;
181
            } else {
182 4
                $type = "{$this->getReflectionClass()->getNamespaceName()}\\$type";
183
            }
184
        }
185
186 4
        $classField->setType($type);
187
188 4
        return $this;
189
    }
190
191
    /**
192
     * @param string $type
193
     * @return bool
194
     */
195 4
    private function typeIsNotStandard(string $type): bool {
196 4
        return !in_array($type, array('int', 'string', 'float', 'bool', 'array'));
197
    }
198
199
}