Completed
Push — master ( f04f52...152406 )
by Anton
03:17
created

src/Visitor/AddProxiedMethods.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license MIT
6
 * @author  Valentin V (Vvval)
7
 */
8
declare(strict_types=1);
9
10
namespace Cycle\ORM\Promise\Visitor;
11
12
use Cycle\ORM\Promise\Expressions;
13
use Cycle\ORM\Promise\PHPDoc;
14
use PhpParser\Builder\Param;
15
use PhpParser\Node;
16
use PhpParser\NodeVisitorAbstract;
17
18
/**
19
 * Add parent call via proxy resolver
20
 */
21
final class AddProxiedMethods extends NodeVisitorAbstract
22
{
23
    /** @var string */
24
    private $resolverProperty;
25
26
    /** @var Node\Stmt\ClassMethod[] */
27
    private $methods;
28
29
    /** @var string */
30
    private $resolveMethod;
31
32
    /**
33
     * @param string $property
34
     * @param array  $methods
35
     * @param string $resolveMethod
36
     */
37
    public function __construct(string $property, array $methods, string $resolveMethod)
38
    {
39
        $this->resolverProperty = $property;
40
        $this->methods = $methods;
41
        $this->resolveMethod = $resolveMethod;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function leaveNode(Node $node)
48
    {
49
        if (!$node instanceof Node\Stmt\Class_) {
50
            return null;
51
        }
52
53
        foreach ($this->methods as $method) {
54
            if ($method->name->name === '__clone') {
55
                $method->stmts = [$this->buildCloneExpression()];
56
                $node->stmts[] = $method;
57
            } elseif ($this->hasReturnStmt($method)) {
58
                $node->stmts[] = $this->modifyReturnMethod($method);
59
            } else {
60
                $node->stmts[] = $this->modifyExprMethod($method);
61
            }
62
        }
63
64
        return $node;
65
    }
66
67
    /**
68
     * @return Node\Stmt\Expression
69
     */
70 View Code Duplication
    private function buildCloneExpression(): Node\Stmt\Expression
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
71
    {
72
        return new Node\Stmt\Expression(
73
            new Node\Expr\Assign(
74
                Expressions::resolvePropertyFetch('this', $this->resolverProperty),
75
                new Node\Expr\Clone_(Expressions::resolvePropertyFetch('this', $this->resolverProperty))
76
            )
77
        );
78
    }
79
80
    /**
81
     * @param Node\Stmt\ClassMethod $method
82
     * @return Node\Stmt\ClassMethod
83
     */
84 View Code Duplication
    private function modifyReturnMethod(Node\Stmt\ClassMethod $method): Node\Stmt\ClassMethod
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
85
    {
86
        $method->setDocComment(PHPDoc::writeInheritdoc());
87
88
        $resolved = Expressions::resolveMethodCall('this', $this->resolverProperty, $this->resolveMethod);
89
        $stmt = new Node\Stmt\Return_(new Node\Expr\MethodCall($resolved, $method->name->name,
90
            $this->packMethodArgs($method)));
91
92
        $method->stmts[] = Expressions::throwExceptionOnNull($resolved, $stmt);
93
94
        return $method;
95
    }
96
97
    /**
98
     * @param Node\Stmt\ClassMethod $method
99
     * @return Node\Stmt\ClassMethod
100
     */
101 View Code Duplication
    private function modifyExprMethod(Node\Stmt\ClassMethod $method): Node\Stmt\ClassMethod
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
    {
103
        $method->setDocComment(PHPDoc::writeInheritdoc());
104
105
        $resolved = Expressions::resolveMethodCall('this', $this->resolverProperty, $this->resolveMethod);
106
        $stmt = new Node\Stmt\Expression(new Node\Expr\MethodCall($resolved, $method->name->name,
107
            $this->packMethodArgs($method)));
108
109
        $method->stmts[] = Expressions::throwExceptionOnNull($resolved, $stmt);
110
111
        return $method;
112
    }
113
114
    /**
115
     * @param Node\Stmt\ClassMethod $method
116
     * @return array
117
     */
118
    private function packMethodArgs(Node\Stmt\ClassMethod $method): array
119
    {
120
        $args = [];
121
        /** @var \PhpParser\Node\Param $param */
122
        foreach ($method->getParams() as $param) {
123
            $args[] = (new Param($param->var->name))->getNode();
124
        }
125
126
        return $args;
127
    }
128
129
    /**
130
     * @param Node\Stmt\ClassMethod $method
131
     * @return bool
132
     */
133
    private function hasReturnStmt(Node\Stmt\ClassMethod $method): bool
134
    {
135
        if ($method->returnType === null || $method->returnType === 'void') {
136
            return false;
137
        }
138
139
        if ($method->returnType instanceof Node\NullableType) {
140
            return true;
141
        }
142
143
        return $method->returnType instanceof Node\Identifier && $method->returnType->name !== 'void';
144
    }
145
}