ClassAliasStmtAppender   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Test Coverage

Coverage 97.56%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 37
dl 0
loc 93
rs 10
c 2
b 0
f 0
ccs 40
cts 41
cp 0.9756
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A afterTraverse() 0 13 3
A appendToNamespaceStmt() 0 9 1
A __construct() 0 8 1
A createNamespaceStmts() 0 25 6
A createAliasStmt() 0 19 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\PhpParser\NodeVisitor;
16
17
use Humbug\PhpScoper\PhpParser\Node\ClassAliasFuncCall;
18
use Humbug\PhpScoper\PhpParser\Node\FullyQualifiedFactory;
19
use Humbug\PhpScoper\PhpParser\NodeVisitor\Resolver\IdentifierResolver;
20
use Humbug\PhpScoper\PhpParser\UnexpectedParsingScenario;
21
use Humbug\PhpScoper\Symbol\EnrichedReflector;
22
use PhpParser\Node;
23
use PhpParser\Node\Name\FullyQualified;
24
use PhpParser\Node\Stmt;
25
use PhpParser\Node\Stmt\Class_;
26
use PhpParser\Node\Stmt\Expression;
27
use PhpParser\Node\Stmt\Interface_;
28
use PhpParser\Node\Stmt\Namespace_;
29
use PhpParser\NodeVisitorAbstract;
30
use function array_reduce;
31
32
/**
33
 * Appends a `class_alias` statement to the exposed classes.
34
 *
35
 * ```
36
 * namespace A;
37
 *
38
 * class Foo
39
 * {
40
 * }
41
 * ```
42
 *
43
 * =>
44
 *
45
 * ```
46
 * namespace Humbug\A;
47
 *
48
 * class Foo
49
 * {
50
 * }
51
 *
52
 * class_alias('Humbug\A\Foo', 'A\Foo', false);
53
 * ```
54
 *
55
 * @internal
56
 */
57
final class ClassAliasStmtAppender extends NodeVisitorAbstract
58
{
59
    private string $prefix;
60
    private EnrichedReflector $enrichedReflector;
61 549
    private IdentifierResolver $identifierResolver;
62
63 549
    public function __construct(
64 549
        string $prefix,
65 549
        EnrichedReflector $enrichedReflector,
66
        IdentifierResolver $identifierResolver
67
    ) {
68
        $this->prefix = $prefix;
69
        $this->enrichedReflector = $enrichedReflector;
70
        $this->identifierResolver = $identifierResolver;
71 548
    }
72
73 548
    public function afterTraverse(array $nodes): array
74
    {
75 548
        $newNodes = [];
76 547
77 545
        foreach ($nodes as $node) {
78
            if ($node instanceof Namespace_) {
79
                $node = $this->appendToNamespaceStmt($node);
80 547
            }
81
82
            $newNodes[] = $node;
83 548
        }
84
85
        return $newNodes;
86 545
    }
87
88 545
    private function appendToNamespaceStmt(Namespace_ $namespace): Namespace_
89 545
    {
90 545
        $namespace->stmts = array_reduce(
91 545
            $namespace->stmts,
92
            fn (array $stmts, Stmt $stmt) => $this->createNamespaceStmts($stmts, $stmt),
93
            [],
94 545
        );
95
96
        return $namespace;
97
    }
98
99
    /**
100 532
     * @param Stmt[] $stmts
101
     *
102 532
     * @return Stmt[]
103
     */
104 532
    private function createNamespaceStmts(array $stmts, Stmt $stmt): array
105 486
    {
106
        $stmts[] = $stmt;
107
108 287
        $isClassOrInterface = $stmt instanceof Class_ || $stmt instanceof Interface_;
109
110
        if (!$isClassOrInterface) {
111
            return $stmts;
112 287
        }
113
114 287
        $name = $stmt->name;
115 287
116
        if (null === $name) {
117 273
            throw UnexpectedParsingScenario::create();
118 245
        }
119
120
        $resolvedName = $this->identifierResolver->resolveIdentifier($name);
121 253
122
        if ($resolvedName instanceof FullyQualified
123
            && $this->enrichedReflector->isExposedClass((string) $resolvedName)
124
        ) {
125 77
            $stmts[] = self::createAliasStmt($resolvedName, $stmt, $this->prefix);
126
        }
127 77
128
        return $stmts;
129
    }
130 77
131
    private static function createAliasStmt(
132 77
        FullyQualified $originalName,
133 77
        Node $stmt,
134 77
        string $prefix
135 77
    ): Expression {
136
        $call = new ClassAliasFuncCall(
137
            FullyQualifiedFactory::concat($prefix, $originalName),
138 77
            $originalName,
139 77
            $stmt->getAttributes(),
140 77
        );
141
142
        $expression = new Expression(
143 77
            $call,
144
            $stmt->getAttributes(),
145 77
        );
146
147
        ParentNodeAppender::setParent($call, $expression);
148
149
        return $expression;
150
    }
151
}
152