Completed
Pull Request — 1.x (#286)
by Alexander
02:43
created

TraitProxy   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 11
c 4
b 0
f 0
lcom 3
cbo 2
dl 0
loc 119
ccs 0
cts 66
cp 0
rs 10

5 Methods

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