Passed
Push — master ( d3a94c...76e109 )
by Valentin
05:50
created

ProxyCreator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 1
nc 1
nop 3
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;
8
use PhpParser\Lexer;
9
use PhpParser\Parser;
10
use PhpParser\PrettyPrinter\Standard;
11
use PhpParser\PrettyPrinterAbstract;
12
13
class ProxyCreator
14
{
15
    private const PROPERTY = '__resolver';
16
17
    private const DEPENDENCIES = [
18
        'orm'    => ORMInterface::class,
19
        'target' => 'string',
20
        'scope'  => 'array'
21
    ];
22
23
    /** @var ConflictResolver */
24
    private $resolver;
25
26
    /** @var Traverser */
27
    private $traverser;
28
29
    /** @var Declaration\Extractor */
30
    private $extractor;
31
32
    /** @var Lexer */
33
    private $lexer;
34
35
    /** @var Parser */
36
    private $parser;
37
38
    /** @var PrettyPrinterAbstract */
39
    private $printer;
40
41
    public function __construct(ConflictResolver $resolver, Traverser $traverser, Declaration\Extractor $extractor)
42
    {
43
        $this->resolver = $resolver;
44
        $this->traverser = $traverser;
45
        $this->extractor = $extractor;
46
47
        $lexer = new Lexer\Emulative([
48
            'usedAttributes' => [
49
                'comments',
50
                'startLine',
51
                'endLine',
52
                'startTokenPos',
53
                'endTokenPos',
54
            ],
55
        ]);
56
57
        $this->lexer = $lexer;
58
        $this->parser = new Parser\Php7($this->lexer);
59
60
        $this->printer = new Standard();
61
    }
62
63
    /**
64
     *
65
     * @param string $class
66
     * @param string $as
67
     *
68
     * @return string
69
     */
70
    public function make(string $class, string $as): string
71
    {
72
        $declaration = $this->extractor->extract($class);
73
        $schema = new Declaration\Schema($class, $as);
74
75
        $property = $this->propertyName($declaration);
76
77
        $visitors = [
78
            new Visitor\AddUseStmts($this->useStmts($schema)),
79
            new Visitor\UpdateNamespace($schema->class->namespace),
80
            new Visitor\DeclareClass($schema->class->class, $schema->extends->class),
81
            new Visitor\AddResolverProperty($property, $this->propertyType(), $schema->extends->class),
82
            new Visitor\UpdateConstructor($declaration->hasConstructor, $property, $this->propertyType(), self::DEPENDENCIES),
83
            new Visitor\UpdatePromiseMethods($property),
84
            new Visitor\AddProxiedMethods($property, $declaration->methods),
85
        ];
86
87
        $nodes = $this->getNodesFromStub();
88
        $output = $this->traverser->traverseClonedNodes($nodes, ...$visitors);
89
90
        return $this->printer->printFormatPreserving(
91
            $output,
92
            $nodes,
0 ignored issues
show
Bug introduced by
It seems like $nodes defined by $this->getNodesFromStub() on line 87 can also be of type null; however, PhpParser\PrettyPrinterA...printFormatPreserving() does only seem to accept array<integer,object<PhpParser\Node>>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
93
            $this->lexer->getTokens()
94
        );
95
    }
96
97
    private function propertyName(Declaration\Declaration $declaration): string
98
    {
99
        return $this->resolver->resolve($declaration->properties, self::PROPERTY);
100
    }
101
102
    private function useStmts(Declaration\Schema $schema): array
103
    {
104
        if ($schema->class->namespace !== $schema->extends->namespace) {
105
            return [$schema->extends->getNamespacesName()];
106
        }
107
108
        return [];
109
    }
110
111
    private function propertyType(): string
112
    {
113
        return Utils::shortName(PromiseResolver::class);
114
    }
115
116
    private function getNodesFromStub()
117
    {
118
        return $this->parser->parse(file_get_contents($this->getStubFilename()));
119
    }
120
121
    private function getStubFilename(): string
122
    {
123
        return dirname(__DIR__) . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'proxy.stub';
124
    }
125
}