Completed
Push — master ( be9e17...f9656a )
by BruceScrutinizer
02:33
created

PhpFileParser::fetchAstAfterParse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 18
rs 9.9332
1
<?php declare(strict_types=1);
2
3
namespace NamespaceProtector\Parser;
4
5
use PhpParser\NodeTraverser;
6
use PhpParser\ParserFactory;
7
use NamespaceProtector\Result\Result;
8
use NamespaceProtector\Parser\Node\PhpNode;
9
use NamespaceProtector\Common\PathInterface;
10
use NamespaceProtector\Result\ResultCollector;
11
use Psr\EventDispatcher\EventDispatcherInterface;
12
use NamespaceProtector\Result\ResultCollectorReadable;
13
use NamespaceProtector\Exception\NamespaceProtectorExceptionInterface;
14
15
final class PhpFileParser implements ParserInterface
16
{
17
    private const ONLY_ONE_ENTRY = 1;
18
19
    /** @var \PhpParser\Parser  */
20
    private $parser;
21
22
    /** @var NodeTraverser  */
23
    private $traverser;
24
25
    /** @var ResultCollector  */
26
    private $resultCollector;
27
28
    /** @var \Psr\SimpleCache\CacheInterface  */
29
    private $cache;
30
31
    public function __construct(
32
        \Psr\SimpleCache\CacheInterface $cache,
33
        EventDispatcherInterface $eventDispatcher
34
    ) {
35
        $this->cache = $cache;
36
        $this->parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
37
        $this->traverser = new NodeTraverser();
38
39
        $this->resultCollector = new ResultCollector();
40
41
        $phpNode = new PhpNode(
42
            ['preserveOriginalNames' => true, 'replaceNodes' => false],
43
            $this->resultCollector,
44
            $eventDispatcher
45
        );
46
47
        $this->traverser->addVisitor($phpNode);
48
    }
49
50
    public function parseFile(PathInterface $pathFile): void
51
    {
52
        $this->resultCollector->emptyResult();
53
        $this->resultCollector->addResult(new Result('Process file: ' . $pathFile() . PHP_EOL));
54
55
        $ast = $this->fetchAstAfterParse($pathFile);
56
57
        $this->traverser->traverse($ast);
58
59
        $this->emptyLogIfNoErrorEntry();
60
    }
61
62
    public function getListResult(): ResultCollectorReadable
63
    {
64
        return new ResultCollectorReadable($this->resultCollector);
65
    }
66
67
    private function emptyLogIfNoErrorEntry(): void
68
    {
69
        if (\count($this->resultCollector->get()) === self::ONLY_ONE_ENTRY) {
70
            $this->resultCollector->emptyResult();
71
        }
72
    }
73
74
    /**
75
     * @return array<mixed>
76
     */
77
    private function fetchAstAfterParse(PathInterface $pathFile): array
78
    {
79
        $code = $pathFile();
80
        $keyEntryForCache = sha1($code) . '.' . base64_encode($pathFile());
81
82
        if (!$this->cache->has($keyEntryForCache)) {
83
            $code = \file_get_contents($pathFile());
84
            if ($code === false) {
85
                throw new \RuntimeException(NamespaceProtectorExceptionInterface::MSG_PLAIN_ERROR_FILE_GET_CONTENT);
86
            }
87
88
            $ast = $this->parser->parse($code);
89
            $this->cache->set($keyEntryForCache, $ast);
90
91
            return $ast ?? [];
92
        }
93
94
        return $this->cache->get($keyEntryForCache, []);
95
    }
96
}
97