ClassesInPackageValidator::getAllFqcnsInDir()   B
last analyzed

Complexity

Conditions 11
Paths 10

Size

Total Lines 46
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
eloc 24
dl 0
loc 46
c 0
b 0
f 0
rs 7.3166
ccs 0
cts 35
cp 0
cc 11
nc 10
nop 2
crap 132

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * File was created 16.10.2015 08:08
4
 */
5
6
namespace PeekAndPoke\Component\Slumber\Helper;
7
8
use Doctrine\Common\Annotations\AnnotationReader;
9
use PeekAndPoke\Component\Psi\Psi;
10
use PeekAndPoke\Component\Slumber\Core\Codec\ArrayCodecPropertyMarker2Mapper;
11
use PeekAndPoke\Component\Slumber\Core\LookUp\AnnotatedEntityConfigReader;
12
use Psr\Container\ContainerInterface;
13
use Psr\Log\LoggerInterface;
14
use Psr\Log\NullLogger;
15
use Symfony\Component\Finder\Finder;
16
use Symfony\Component\Finder\SplFileInfo;
17
18
/**
19
 * @author Karsten J. Gerber <[email protected]>
20
 */
21
class ClassesInPackageValidator
22
{
23
    /** @var ContainerInterface */
24
    private $provider;
25
    /** @var LoggerInterface */
26
    private $logger;
27
28
    /**
29
     * ClassesInPackageValidator constructor.
30
     *
31
     * @param ContainerInterface   $provider
32
     * @param LoggerInterface|null $logger
33
     */
34
    public function __construct(ContainerInterface $provider, LoggerInterface $logger = null)
35
    {
36
        $this->provider = $provider;
37
        $this->logger   = $logger ?: new NullLogger();
38
    }
39
40
    /**
41
     * @param string|string[] $directories
42
     * @param string|string[] $excludeDirs
43
     *
44
     * @return string[]
45
     */
46
    public function validate($directories, array $excludeDirs = [])
47
    {
48
        $fqcns  = $this->getAllFqcnsInDir($directories, $excludeDirs);
49
        $lookUp = new AnnotatedEntityConfigReader(
50
            $this->provider,
51
            new AnnotationReader(),
52
            new ArrayCodecPropertyMarker2Mapper()
53
        );
54
55
        $errors = [];
56
57
        if (\count($fqcns) === 0) {
58
            $errors[] = 'No classes found in dirs ' . implode(', ', (array) $directories);
59
        }
60
61
        foreach ($fqcns as $fqcn) {
62
63
            try {
64
                $reflect = new \ReflectionClass($fqcn);
65
66
                $this->logger->info('validating ' . $fqcn);
67
                $lookUp->getEntityConfig($reflect);
68
                $this->logger->info('... OK');
69
70
            } catch (\Exception $e) {
71
                $msg      = $e->getMessage() . ' used in class ' . $fqcn;
72
                $errors[] = $msg;
73
74
                $this->logger->error($msg);
75
            }
76
        }
77
78
        return $errors;
79
    }
80
81
    /**
82
     * @param string|string[] $directories
83
     * @param string|string[] $excludeDirs
84
     *
85
     * @return string[]
86
     */
87
    private function getAllFqcnsInDir($directories, $excludeDirs)
88
    {
89
        $finder = (new Finder())->name('*.php')->in($directories);
90
        $fqcns  = [];
91
92
        /** @var SplFileInfo $item */
93
        foreach ($finder->getIterator() as $item) {
94
95
            // we have to exclude manually since it does not work on the finder when using exclude()
96
            $excludeIt = Psi::it($excludeDirs)
97
                ->filter(function ($dir) use ($item) {
98
                    return strpos($item->getRealPath(), $dir) === 0;
99
                })
100
                ->count();
101
102
            if ($excludeIt) {
103
                continue;
104
            }
105
106
            $tokens    = token_get_all($item->getContents());
107
            $namespace = '';
108
109
            for ($index = 0; isset($tokens[$index]); $index++) {
110
                if (! isset($tokens[$index][0])) {
111
                    continue;
112
                }
113
                if (T_NAMESPACE === $tokens[$index][0]) {
114
                    $index += 2; // Skip namespace keyword and whitespace
115
                    while (isset($tokens[$index]) && \is_array($tokens[$index])) {
116
                        $namespace .= $tokens[$index++][1];
117
                    }
118
                }
119
120
                if (T_CLASS === $tokens[$index][0] && \count($tokens[$index + 2]) > 1) {
121
                    $index += 2; // Skip class keyword and whitespace
122
123
                    $fqcn = $namespace . '\\' . $tokens[$index][1];
124
125
                    if (class_exists($fqcn)) {
126
                        $fqcns[] = $namespace . '\\' . $tokens[$index][1];
127
                    }
128
                }
129
            }
130
        }
131
132
        return $fqcns;
133
    }
134
}
135