Completed
Push — master ( 509a2e...170574 )
by Alexander
07:07
created

TraitProxy::getJoinPoint()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 21
ccs 0
cts 15
cp 0
rs 9.3142
cc 3
eloc 11
nc 4
nop 4
crap 12
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 (!isset($accessor)) {
60
            $aspectKernel = AspectKernel::getInstance();
61
            $accessor     = $aspectKernel->getContainer()->get('aspect.advisor.accessor');
62
        }
63
64
        $advices = self::$traitAdvices[$traitName][$joinPointType][$pointName];
65
66
        $filledAdvices = [];
67
        foreach ($advices as $advisorName) {
68
            $filledAdvices[] = $accessor->$advisorName;
69
        }
70
71
        $joinpoint = new self::$invocationClassMap[$joinPointType]($className, $pointName . '➩', $filledAdvices);
72
73
        return $joinpoint;
74
    }
75
76
    /**
77
     * Creates definition for trait method body
78
     *
79
     * @param ParsedMethod $method Method reflection
80
     *
81
     * @return string new method body
82
     */
83
    protected function getJoinpointInvocationBody(ParsedMethod $method)
84
    {
85
        $isStatic = $method->isStatic();
86
        $class    = '\\' . __CLASS__;
87
        $scope    = $isStatic ? self::$staticLsbExpression : '$this';
88
        $prefix   = $isStatic ? AspectContainer::STATIC_METHOD_PREFIX : AspectContainer::METHOD_PREFIX;
89
90
        $args = $this->prepareArgsLine($method);
91
        $args = $scope . ($args ? ", [$args]" : '');
92
93
        return <<<BODY
94
static \$__joinPoint = null;
95
if (!\$__joinPoint) {
96
    \$__joinPoint = {$class}::getJoinPoint(__TRAIT__, __CLASS__, '{$prefix}', '{$method->name}');
97
}
98
return \$__joinPoint->__invoke($args);
99
BODY;
100
    }
101
102
    /**
103
     * {@inheritDoc}
104
     */
105
    public function __toString()
106
    {
107
        $classCode = (
108
            $this->class->getDocComment() . "\n" . // Original doc-block
109
            'trait ' . // 'trait' keyword
110
            $this->name . "\n" . // Name of the trait
111
            "{\n" . // Start of trait body
112
            $this->indent(
113
                'use ' . join(', ', array(-1 => $this->parentClassName) + $this->traits) .
114
                $this->getMethodAliasesCode()
115
            ) . "\n" . // Use traits and aliases section
116
            $this->indent(join("\n", $this->methodsCode)) . "\n" . // Method definitions
117
            "}" // End of trait body
118
        );
119
120
        return $classCode
121
            // Inject advices on call
122
            . PHP_EOL
123
            . '\\' . __CLASS__ . "::injectJoinPoints('"
124
                . $this->class->name . "',"
125
                . var_export($this->advices, true) . ");";
126
    }
127
128
    private function getMethodAliasesCode()
129
    {
130
        $aliasesLines = [];
131
        foreach (array_keys($this->methodsCode) as $methodName) {
132
            $aliasesLines[] = "{$this->parentClassName}::{$methodName} as protected {$methodName}➩;";
133
        }
134
135
        return "{\n " . $this->indent(join("\n", $aliasesLines)) . "\n}";
136
    }
137
}
138