Completed
Push — master ( 480c88...01d8db )
by Valentin
08:43
created

ProxyPrinter::initMethodName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Cycle\ORM\Promise;
5
6
use Cycle\ORM\ORMInterface;
7
use Cycle\ORM\Promise\Declaration\DeclarationInterface;
8
use Cycle\ORM\Promise\Declaration\Extractor;
9
use Cycle\ORM\Promise\Declaration\Structure;
10
use PhpParser\Lexer;
11
use PhpParser\Node;
12
use PhpParser\Parser;
13
use PhpParser\PrettyPrinter\Standard;
14
use PhpParser\PrettyPrinterAbstract;
15
16
class ProxyPrinter
17
{
18
    private const RESOLVER_PROPERTY = '__resolver';
19
    private const UNSET_PROPERTIES  = 'UNSET_PROPERTIES';
20
    private const RESOLVE_METHOD    = '__resolve';
21
    private const INIT_METHOD       = '__init';
22
23
    private const DEPENDENCIES = [
24
        'orm'   => ORMInterface::class,
25
        'role'  => 'string',
26
        'scope' => 'array'
27
    ];
28
29
    private const USE_STMTS = [
30
        PromiseResolver::class,
31
        PromiseException::class,
32
        ORMInterface::class
33
    ];
34
35
    /** @var ConflictResolver */
36
    private $resolver;
37
38
    /** @var Traverser */
39
    private $traverser;
40
41
    /** @var Extractor */
42
    private $extractor;
43
44
    /** @var Lexer */
45
    private $lexer;
46
47
    /** @var Parser */
48
    private $parser;
49
50
    /** @var PrettyPrinterAbstract */
51
    private $printer;
52
53
    /** @var Stubs */
54
    private $stubs;
55
56
    public function __construct(ConflictResolver $resolver, Traverser $traverser, Extractor $extractor, Stubs $stubs)
57
    {
58
        $this->resolver = $resolver;
59
        $this->traverser = $traverser;
60
        $this->extractor = $extractor;
61
62
        $lexer = new Lexer\Emulative([
63
            'usedAttributes' => [
64
                'comments',
65
                'startLine',
66
                'endLine',
67
                'startTokenPos',
68
                'endTokenPos',
69
            ],
70
        ]);
71
72
        $this->lexer = $lexer;
73
        $this->parser = new Parser\Php7($this->lexer);
74
75
        $this->printer = new Standard();
76
        $this->stubs = $stubs;
77
    }
78
79
    public function make(\ReflectionClass $reflection, DeclarationInterface $class, DeclarationInterface $parent): string
80
    {
81
        $structure = $this->extractor->extract($reflection);
82
83
        $property = $this->resolverPropertyName($structure);
84
        $unsetPropertiesConst = $this->unsetPropertiesConstName($structure);
85
86
        $visitors = [
87
            new Visitor\AddUseStmts($this->useStmts($class, $parent)),
88
            new Visitor\UpdateNamespace($class->getNamespaceName()),
89
            new Visitor\DeclareClass($class->getShortName(), $parent->getShortName()),
90
            new Visitor\AddUnsetPropertiesConst($unsetPropertiesConst, $structure->properties),
91
            new Visitor\AddResolverProperty($property, $this->propertyType(), $parent->getShortName()),
92
            new Visitor\AddInit(
93
                $property,
94
                $this->propertyType(),
95
                self::DEPENDENCIES,
96
                $this->unsetPropertiesConstName($structure),
97
                $this->initMethodName($structure)
98
            ),
99
            new Visitor\AddMagicClone($property, $structure->hasClone),
100
            new Visitor\AddMagicGet($property, self::RESOLVE_METHOD),
101
            new Visitor\AddMagicSet($property, self::RESOLVE_METHOD),
102
            new Visitor\AddMagicIsset($property, self::RESOLVE_METHOD, $unsetPropertiesConst),
103
            new Visitor\AddMagicUnset($property, self::RESOLVE_METHOD, $unsetPropertiesConst),
104
            new Visitor\AddMagicDebugInfo($property, self::RESOLVE_METHOD, $structure->properties),
105
            new Visitor\UpdatePromiseMethods($property),
106
            new Visitor\AddProxiedMethods($property, $structure->methods, self::RESOLVE_METHOD),
107
        ];
108
109
        $nodes = $this->getNodesFromStub();
110
        $output = $this->traverser->traverseClonedNodes($nodes, ...$visitors);
111
112
        return $this->printer->printFormatPreserving(
113
            $output,
114
            $nodes,
115
            $this->lexer->getTokens()
116
        );
117
    }
118
119
    public function initMethodName(Structure $structure): string
120
    {
121
        return $this->resolver->resolve($structure->methodNames(), self::INIT_METHOD)->fullName();
122
    }
123
124
    private function resolverPropertyName(Structure $structure): string
125
    {
126
        return $this->resolver->resolve($structure->properties, self::RESOLVER_PROPERTY)->fullName();
127
    }
128
129
    private function unsetPropertiesConstName(Structure $structure): string
130
    {
131
        return $this->resolver->resolve($structure->constants, self::UNSET_PROPERTIES)->fullName('_');
132
    }
133
134
    private function useStmts(DeclarationInterface $class, DeclarationInterface $parent): array
135
    {
136
        $useStmts = self::USE_STMTS;
137
        if ($class->getNamespaceName() !== $parent->getNamespaceName()) {
138
            $useStmts[] = $parent->getFullName();
139
        }
140
141
        return $useStmts;
142
    }
143
144
    private function propertyType(): string
145
    {
146
        return Utils::shortName(PromiseResolver::class);
147
    }
148
149
    /**
150
     * @return Node\Stmt[]
151
     */
152
    private function getNodesFromStub(): array
153
    {
154
        return $this->parser->parse($this->stubs->getContent()) ?? [];
155
    }
156
}