Completed
Branch 2.x (867c01)
by Akihito
09:30
created

Bind   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 19
Bugs 4 Features 3
Metric Value
wmc 21
c 19
b 4
f 3
lcom 1
cbo 4
dl 0
loc 161
ccs 64
cts 64
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A annotatedMethodsMatch() 0 7 2
A annotatedMethodMatch() 0 17 4
A annotatedMethodMatchBind() 0 12 3
A getBindings() 0 4 1
A toString() 0 8 1
A getAnnotationPointcuts() 0 12 3
A onionOrderMatch() 0 17 3
A bind() 0 7 1
A bindInterceptors() 0 9 2
1
<?php
2
/**
3
 * This file is part of the Ray.Aop package
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace Ray\Aop;
8
9
use Doctrine\Common\Annotations\AnnotationReader;
10
11
final class Bind implements BindInterface
12
{
13
    /**
14
     * @var array
15
     */
16
    private $bindings = [];
17
18
    /**
19
     * @var AnnotationReader
20
     */
21
    private $reader;
22
23 32
    public function __construct()
24
    {
25 32
        $this->reader = new AnnotationReader();
26 32
    }
27
28
    /**
29
     * @param string $class
30
     * @param array  $pointcuts
31
     *
32
     * @return $this
33
     */
34 30
    public function bind($class, array $pointcuts)
1 ignored issue
show
Best Practice introduced by
Using PHP4-style constructors that are named like the class is not recommend; better use the more explicit __construct method.
Loading history...
35
    {
36 30
        $pointcuts = $this->getAnnotationPointcuts($pointcuts);
37 30
        $this->annotatedMethodsMatch(new \ReflectionClass($class), $pointcuts);
38
39 30
        return $this;
40
    }
41
42
    /**
43
     * @param ReflectionClass $class
44
     * @param Pointcut[]      $pointcuts
45
     */
46 30
    private function annotatedMethodsMatch(\ReflectionClass $class, array &$pointcuts)
47
    {
48 30
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
49 30
        foreach ($methods as $method) {
50 30
            $this->annotatedMethodMatch($class, $method, $pointcuts);
51 30
        }
52 30
    }
53
54
    /**
55
     * @param ReflectionClass  $class
56
     * @param ReflectionMethod $method
57
     * @param Pointcut[]       $pointcuts
58
     */
59 30
    private function annotatedMethodMatch(\ReflectionClass $class, \ReflectionMethod $method, array $pointcuts)
60
    {
61 30
        $annotations = $this->reader->getMethodAnnotations($method);
62
        // priority bind
63 30
        foreach ($pointcuts as $key => $pointcut) {
64 30
            if ($pointcut instanceof PriorityPointcut) {
65 1
                $this->annotatedMethodMatchBind($class, $method, $pointcut);
66 1
                unset($pointcuts[$key]);
67 1
            }
68 30
        }
69 30
        $onion = $this->onionOrderMatch($class, $method, $pointcuts, $annotations);
70
71
        // default binding
72 30
        foreach ($onion as $pointcut) {
73 30
            $this->annotatedMethodMatchBind($class, $method, $pointcut);
74 30
        }
75 30
    }
76
77
    /**
78
     * @param ReflectionClass  $class
79
     * @param ReflectionMethod $method
80
     * @param PointCut         $pointCut
81
     */
82 30
    private function annotatedMethodMatchBind(\ReflectionClass $class, \ReflectionMethod $method, PointCut $pointCut)
83
    {
84 30
        $isMethodMatch = $pointCut->methodMatcher->matchesMethod($method, $pointCut->methodMatcher->getArguments());
85 30
        if (! $isMethodMatch) {
86 25
            return;
87
        }
88 30
        $isClassMatch = $pointCut->classMatcher->matchesClass($class, $pointCut->classMatcher->getArguments());
89 30
        if (! $isClassMatch) {
90 2
            return;
91
        }
92 28
        $this->bindInterceptors($method->name, $pointCut->interceptors);
93 28
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 30
    public function bindInterceptors($method, array $interceptors)
99
    {
100 30
        $this->bindings[$method] = !isset($this->bindings[$method]) ? $interceptors : array_merge(
101 3
            $this->bindings[$method],
102
            $interceptors
103 3
        );
104
105 30
        return $this;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111 26
    public function getBindings()
112
    {
113 26
        return $this->bindings;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function toString($salt)
120
    {
121 17
        $shortHash = function ($data) {
122 17
            return strtr(rtrim(base64_encode(pack('H*', sprintf('%u', crc32(serialize($data))))), '='), '+/', '-_');
123 17
        };
124
125 17
        return $shortHash(serialize($this->bindings) . $salt);
126
    }
127
128
    /**
129
     * @param Pointcut[] $pointcuts
130
     *
131
     * @return Pointcut[]
132
     */
133 30
    public function getAnnotationPointcuts(array &$pointcuts)
134
    {
135 30
        $keyPointcuts = [];
136 30
        foreach ($pointcuts as $key => $pointcut) {
137 30
            if ($pointcut->methodMatcher instanceof AnnotatedMatcher) {
138 2
                $key = $pointcut->methodMatcher->annotation;
139 2
            }
140 30
            $keyPointcuts[$key] = $pointcut;
141 30
        }
142
143 30
        return $keyPointcuts;
144
    }
145
146
    /**
147
     * @param ReflectionClass  $class
148
     * @param ReflectionMethod $method
149
     * @param Pointcut[]       $pointcuts
150
     * @param array            $annotations
151
     *
152
     * @return array
153
     */
154 30
    private function onionOrderMatch(
155
        \ReflectionClass $class,
156
        \ReflectionMethod $method,
157
        array $pointcuts,
158
        $annotations
159
    ) {
160
        // method bind in annotation order
161 30
        foreach ($annotations as $annotation) {
162 7
            $annotationIndex = get_class($annotation);
163 7
            if (isset($pointcuts[$annotationIndex])) {
164 2
                $this->annotatedMethodMatchBind($class, $method, $pointcuts[$annotationIndex]);
165 2
                unset($pointcuts[$annotationIndex]);
166 2
            }
167 30
        }
168
169 30
        return $pointcuts;
170
    }
171
}
172