Completed
Push — master ( 412e57...d404ac )
by Alexander
04:50
created

TraitProxy::getJoinpointInvocationBody()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 18
rs 9.2
cc 4
eloc 12
nc 8
nop 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 View Code Duplication
        if (empty(self::$invocationClassMap)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
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