NamespaceCrawler::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 3
nc 4
nop 2
1
<?php
2
/**
3
 * This program is free software. It comes without any warranty, to
4
 * the extent permitted by applicable law. You can redistribute it
5
 * and/or modify it under the terms of the Do What The Fuck You Want
6
 * To Public License, Version 2, as published by Sam Hocevar. See
7
 * http://www.wtfpl.net/ for more details.
8
 */
9
10
declare(strict_types = 1);
11
12
namespace hanneskod\classtools\Transformer\Action;
13
14
use hanneskod\classtools\Name;
15
use hanneskod\classtools\Exception\RuntimeException;
16
use PhpParser\NodeVisitorAbstract;
17
use PhpParser\Node;
18
use PhpParser\Node\Name\FullyQualified;
19
20
/**
21
 * Search namespaces for definied classes
22
 *
23
 * Crawl namespaces for classes that were wrongly put in namespace by NameResolver
24
 * (if code is moved to the namespace before parsing takes place).
25
 *
26
 * @author Hannes Forsgård <[email protected]>
27
 */
28
class NamespaceCrawler extends NodeVisitorAbstract
29
{
30
    /**
31
     * @var Name[] List of namespaces to test for each undefined name
32
     */
33
    private $search = [];
34
35
    /**
36
     * @var Name[] List of namespaces that will be allowed even if not defined
37
     */
38
    private $whitelist = [];
39
40
    /**
41
     * Search namespaces for definied classes
42
     *
43
     * @param string[] $search    List of namespaces to test for each undefined name
44
     * @param string[] $whitelist namespaces that will be allowed even if not defined
45
     */
46
    public function __construct(array $search, array $whitelist = array())
47
    {
48
        foreach ($search as $namespace) {
49
            $this->search[] = new Name((string)$namespace);
50
        }
51
52
        foreach ($whitelist as $namespace) {
53
            $this->whitelist[] = new Name((string)$namespace);
54
        }
55
    }
56
57
    /**
58
     * Resolve unexisting names by searching specified namespaces
59
     *
60
     * @throws RuntimeException If name can not be resolved
61
     */
62
    public function leaveNode(Node $node)
63
    {
64
        if ($node instanceof FullyQualified) {
65
            $name = new Name((string)$node);
66
            $whitelisted = $this->isWhitelisted($name);
67
            if (!$name->isDefined(!$whitelisted)) {
68
                /** @var Name $namespace */
69
                foreach ($this->search as $namespace) {
70
                    $newName = new Name("{$namespace}\\{$node->getLast()}");
71
                    if ($newName->isDefined()) {
72
                        return $newName->createNode();
73
                    }
74
                }
75
                if (!$whitelisted) {
76
                    throw new RuntimeException("Unable to resolve class <$node>.");
77
                }
78
            }
79
        }
80
    }
81
82
    /**
83
     * Check if name is whitelisted
84
     *
85
     * @param  Name $name
86
     * @return bool
87
     */
88
    public function isWhitelisted(Name $name): bool
89
    {
90
        /** @var Name $namespace */
91
        foreach ($this->whitelist as $namespace) {
92
            if ($name->inNamespace($namespace)) {
93
                return true;
94
            }
95
        }
96
        return false;
97
    }
98
}
99