VarTypeResolver::getFqnFromFileName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Larapie\DataTransferObject\Resolvers;
4
5
use ReflectionProperty;
6
use phpDocumentor\Reflection\TypeResolver;
7
use phpDocumentor\Reflection\Types\Compound;
8
use phpDocumentor\Reflection\Types\ContextFactory;
9
use Larapie\DataTransferObject\Exceptions\TypeDoesNotExistException;
10
11
class VarTypeResolver
12
{
13
    protected $reflection;
14
15
    /** @var string[] List of recognized keywords and unto which Value Object they map */
16
    private static $typeKeywords = [
17
        'string',
18
        'int',
19
        'integer',
20
        'bool',
21
        'boolean',
22
        'float',
23
        'double',
24
        'object',
25
        'mixed',
26
        'array',
27
        'resource',
28
        'void',
29
        'null',
30
        'scalar',
31
        'callback',
32
        'callable',
33
        'false',
34
        'true',
35
        'self',
36
        '$this',
37
        'static',
38
        'parent',
39
        'iterable',
40
    ];
41
42
    /**
43
     * VarTypeResolver constructor.
44
     * @param $reflection
45
     */
46 35
    public function __construct(ReflectionProperty $reflection)
47
    {
48 35
        $this->reflection = $reflection;
49 35
    }
50
51 35
    public function resolve(string $varDocComment) :array
52
    {
53 35
        $contextFactory = new ContextFactory();
54 35
        if ($this->reflection->getDeclaringClass()->isAnonymous()) {
55 22
            $filename = $this->reflection->getDeclaringClass()->getFileName();
56 22
            $context = $contextFactory->createForNamespace($this->getNamespaceFromFilename($filename), file_get_contents($filename));
57
        } else {
58 13
            $context = $contextFactory->createFromReflector($this->reflection);
59
        }
60
61 35
        $resolver = new TypeResolver();
62 35
        $resolvedTypes = $resolver->resolve($varDocComment, $context);
63 35
        $types = [];
64 35
        if ($resolvedTypes instanceof Compound) {
65 5
            foreach ($resolvedTypes as $type) {
66 5
                $types[] = $type->__toString();
67
            }
68
        } else {
69 31
            $types = [$resolvedTypes->__toString()];
70
        }
71 35
        $this->checkTypeExistence($types);
72
73 34
        return $types;
74
    }
75
76
    protected function getClassFromFilename($fileName) :string
77
    {
78
        $directoriesAndFilename = explode('/', $fileName);
79
        $fileName = array_pop($directoriesAndFilename);
80
        $nameAndExtension = explode('.', $fileName);
81
82
        return array_shift($nameAndExtension);
83
    }
84
85 22
    protected function getNamespaceFromFilename($filename) :string
86
    {
87 22
        $lines = file($filename);
88 22
        $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

88
        $namespace = preg_grep('/^namespace /', /** @scrutinizer ignore-type */ $lines);
Loading history...
89 22
        $namespaceLine = array_shift($namespace);
90 22
        $match = [];
91 22
        preg_match('/^namespace (.*);$/', $namespaceLine, $match);
92
93 22
        return $fullNamespace = array_pop($match);
0 ignored issues
show
Unused Code introduced by
The assignment to $fullNamespace is dead and can be removed.
Loading history...
94
    }
95
96
    protected function getFqnFromFileName($fileName) :string
97
    {
98
        return $this->getNamespaceFromFilename($fileName).'\\'.$this->getClassFromFilename($fileName);
99
    }
100
101 35
    protected function checkTypeExistence(array $types)
102
    {
103 35
        foreach ($types as $type) {
104 35
            $type = str_replace('[]', '', $type);
105 35
            if (! in_array($type, self::$typeKeywords)) {
106 10
                if (! $this->classExists($type)) {
107 1
                    throw new TypeDoesNotExistException(sprintf(
108
                        'The @var annotation on %s::%s contains a non existent class "%s". '
109 1
                        .'Did you maybe forget to add a "use" statement for this annotation?',
110 1
                        $this->reflection->getDeclaringClass()->getName(),
111 1
                        $this->reflection->getName(),
112 35
                        $type
113
                    ));
114
                }
115
            }
116
        }
117 34
    }
118
119
    /**
120
     * @param string $class
121
     * @return bool
122
     */
123 10
    private function classExists($class)
124
    {
125 10
        return class_exists($class) || interface_exists($class);
126
    }
127
}
128