Passed
Push — master ( d78e05...9581df )
by Arthur
06:39 queued 29s
created

TypeResolver::resolveTypesFromVarDoc()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 23
rs 9.7333
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
namespace Larapie\DataTransferObject\Resolvers;
4
5
use phpDocumentor\Reflection\Types\Compound;
6
use ReflectionProperty;
7
use Larapie\DataTransferObject\PropertyType;
8
9
class TypeResolver
10
{
11
    /**
12
     * @var ReflectionProperty
13
     */
14
    protected $reflection;
15
16
    /**
17
     * TypeResolver constructor.
18
     * @param ReflectionProperty $reflection
19
     */
20
    public function __construct(ReflectionProperty $reflection)
21
    {
22
        $this->reflection = $reflection;
23
    }
24
25
    /**
26
     * @return PropertyType
27
     */
28
    public function resolve(): PropertyType
29
    {
30
        $type = new PropertyType();
31
32
        $docComment = $this->reflection->getDocComment();
33
34
        if (!$docComment) {
35
            $type->setNullable(true);
36
37
            return $type;
38
        }
39
40
        preg_match('/\@var ((?:(?:[\w|\\\\])+(?:\[\])?)+)/', $docComment, $matches);
0 ignored issues
show
Bug introduced by
It seems like $docComment can also be of type true; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
        preg_match('/\@var ((?:(?:[\w|\\\\])+(?:\[\])?)+)/', /** @scrutinizer ignore-type */ $docComment, $matches);
Loading history...
41
42
        if (!count($matches)) {
43
            $type->setNullable(true);
44
45
            return $type;
46
        }
47
48
        $varDocComment = end($matches);
49
50
51
        $types = $this->resolveTypesFromVarDoc($varDocComment);
52
53
        $type->setTypes($types);
54
        $type->setArrayTypes(str_replace('[]', '', $types));
55
        $type->setHasType(true);
56
        $type->setNullable(strpos($varDocComment, 'null') !== false);
57
58
        return $type;
59
    }
60
61
    protected function resolveTypesFromVarDoc(string $varDocComment)
62
    {
63
        if ($this->reflection->getDeclaringClass()->isAnonymous()) {
64
            $filename = $this->reflection->getDeclaringClass()->getFileName();
65
66
            $contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
67
            $context = $contextFactory->createForNamespace($this->getNamespaceFromFilename($filename), file_get_contents($filename));
68
        } else {
69
            $contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
70
            $context = $contextFactory->createFromReflector($this->reflection);
71
        }
72
73
        $resolver = new \phpDocumentor\Reflection\TypeResolver();
74
        $resolvedTypes = $resolver->resolve($varDocComment, $context);
75
        $types = [];
76
        if ($resolvedTypes instanceof Compound) {
77
            foreach ($resolvedTypes as $type) {
78
                $types[] = $type->__toString();
79
            }
80
        } else {
81
            $types = [$resolvedTypes->__toString()];
82
        }
83
        return $types;
84
    }
85
86
    protected function getClassFromFilename($fileName)
87
    {
88
        $directoriesAndFilename = explode('/', $fileName);
89
        $fileName = array_pop($directoriesAndFilename);
90
        $nameAndExtension = explode('.', $fileName);
91
        $className = array_shift($nameAndExtension);
92
93
        return $className;
94
    }
95
96
    protected function getNamespaceFromFilename($filename)
97
    {
98
        $lines = file($filename);
99
        $namespace = preg_grep('/^namespace /', $lines);
0 ignored issues
show
Bug introduced by
It seems like $lines can also be of type false; however, parameter $input of preg_grep() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
        $namespace = preg_grep('/^namespace /', /** @scrutinizer ignore-type */ $lines);
Loading history...
100
        $namespaceLine = array_shift($namespace);
101
        $match = array();
102
        preg_match('/^namespace (.*);$/', $namespaceLine, $match);
103
        $fullNamespace = array_pop($match);
104
105
        return $fullNamespace;
106
    }
107
108
    protected function getFqnFromFileName($fileName)
109
    {
110
        return $this->getNamespaceFromFilename($fileName) . '\\' . $this->getClassFromFilename($fileName);
111
    }
112
113
114
}
115