Completed
Pull Request — master (#440)
by
unknown
25:11
created

TraitProxy   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
wmc 14
lcom 3
cbo 2
dl 0
loc 118
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A injectJoinPoints() 0 4 1
A getJoinPoint() 0 21 3
B getJoinpointInvocationBody() 0 27 7
A __toString() 0 22 1
A getMethodAliasesCode() 0 9 2
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\Proxy;
12
13
use Go\Core\AspectContainer;
14
use Go\Core\AspectKernel;
15
use Go\Core\LazyAdvisorAccessor;
16
use ReflectionMethod;
17
18
/**
19
 * Trait proxy builder that is used to generate a trait from the list of joinpoints
20
 */
21
class TraitProxy extends ClassProxy
22
{
23
24
    /**
25
     * List of advices for traits
26
     *
27
     * @var array
28
     */
29
    protected static $traitAdvices = [];
30
31
    /**
32
     * Inject advices for given trait
33
     *
34
     * NB This method will be used as a callback during source code evaluation to inject joinpoints
35
     *
36
     * @param string $className Aop child proxy class
37
     * @param array|\Go\Aop\Advice[] $traitAdvices List of advices to inject into class
38
     *
39
     * @return void
40
     */
41
    public static function injectJoinPoints($className, array $traitAdvices = [])
42
    {
43
        self::$traitAdvices[$className] = $traitAdvices;
44
    }
45
46
    public static function getJoinPoint($traitName, $className, $joinPointType, $pointName)
47
    {
48
        /** @var LazyAdvisorAccessor $accessor */
49
        static $accessor;
50
51
        if (!isset($accessor)) {
52
            $aspectKernel = AspectKernel::getInstance();
53
            $accessor     = $aspectKernel->getContainer()->get('aspect.advisor.accessor');
54
        }
55
56
        $advices = self::$traitAdvices[$traitName][$joinPointType][$pointName];
57
58
        $filledAdvices = [];
59
        foreach ($advices as $advisorName) {
60
            $filledAdvices[] = $accessor->$advisorName;
61
        }
62
63
        $joinpoint = new self::$invocationClassMap[$joinPointType]($className, $pointName . '➩', $filledAdvices);
64
65
        return $joinpoint;
66
    }
67
68
    /**
69
     * Creates definition for trait method body
70
     *
71
     * @param ReflectionMethod $method Method reflection
72
     *
73
     * @return string new method body
74
     */
75
    protected function getJoinpointInvocationBody(ReflectionMethod $method)
76
    {
77
        $isStatic = $method->isStatic();
78
        $class    = '\\' . __CLASS__;
79
        $scope    = $isStatic ? self::$staticLsbExpression : '$this';
80
        $prefix   = $isStatic ? AspectContainer::STATIC_METHOD_PREFIX : AspectContainer::METHOD_PREFIX;
81
82
        $args = $this->prepareArgsLine($method);
83
        $args = $scope . ($args ? ", $args" : '');
84
85
        $return = 'return ';
86
        if (PHP_VERSION_ID >= 70100 && $method->hasReturnType()) {
87
            $returnType = (string) $method->getReturnType();
88
            if ($returnType === 'void') {
89
                // void return types should not return anything
90
                $return = '';
91
            }
92
        }
93
94
        return <<<BODY
95
static \$__joinPoint;
96
if (!\$__joinPoint) {
97
    \$__joinPoint = {$class}::getJoinPoint(__TRAIT__, __CLASS__, '{$prefix}', '{$method->name}');
98
}
99
{$return}\$__joinPoint->__invoke($args);
100
BODY;
101
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106
    public function __toString()
107
    {
108
        $classCode = (
109
            $this->class->getDocComment() . "\n" . // Original doc-block
110
            'trait ' . // 'trait' keyword
111
            $this->name . "\n" . // Name of the trait
112
            "{\n" . // Start of trait body
113
            $this->indent(
114
                'use ' . implode(', ', [-1 => $this->parentClassName] + $this->traits) .
115
                $this->getMethodAliasesCode()
116
            ) . "\n" . // Use traits and aliases section
117
            $this->indent(implode("\n", $this->methodsCode)) . "\n" . // Method definitions
118
            '}' // End of trait body
119
        );
120
121
        return $classCode
122
            // Inject advices on call
123
            . PHP_EOL
124
            . '\\' . __CLASS__ . "::injectJoinPoints('"
125
                . $this->class->name . "',"
126
                . var_export($this->advices, true) . ');';
127
    }
128
129
    private function getMethodAliasesCode()
130
    {
131
        $aliasesLines = [];
132
        foreach (array_keys($this->methodsCode) as $methodName) {
133
            $aliasesLines[] = "{$this->parentClassName}::{$methodName} as protected {$methodName}➩;";
134
        }
135
136
        return "{\n " . $this->indent(implode("\n", $aliasesLines)) . "\n}";
137
    }
138
}
139