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

AbstractAspectLoaderExtension   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 9.52%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 12
lcom 1
cbo 3
dl 0
loc 118
ccs 4
cts 42
cp 0.0952
rs 10
c 1
b 1
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A parsePointcut() 0 6 1
B makeLexicalAnalyze() 0 23 5
B parseTokenStream() 0 27 5
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\Core;
12
13
use Dissect\Lexer\Exception\RecognitionException;
14
use Dissect\Lexer\Lexer;
15
use Dissect\Lexer\TokenStream\TokenStream;
16
use Dissect\Parser\Exception\UnexpectedTokenException;
17
use Dissect\Parser\Parser;
18
use Go\Aop\Aspect;
19
use Go\Aop\Pointcut;
20
use Go\Aop\PointFilter;
21
use Go\Lang\Annotation;
22
use ReflectionMethod;
23
use ReflectionProperty;
24
25
/**
26
 * Abstract aspect loader
27
 */
28
abstract class AbstractAspectLoaderExtension implements AspectLoaderExtension
29
{
30
31
    /**
32
     * Instance of pointcut lexer
33
     *
34
     * @var null|Lexer
35
     */
36
    protected $pointcutLexer = null;
37
38
    /**
39
     * Instance of pointcut parser
40
     *
41
     * @var null|Parser
42
     */
43
    protected $pointcutParser = null;
44
45
    /**
46
     * Default initialization of dependencies
47
     *
48
     * @param Lexer $pointcutLexer Instance of pointcut lexer
49
     * @param Parser $pointcutParser Instance of pointcut parser
50
     */
51 2
    public function __construct(Lexer $pointcutLexer, Parser $pointcutParser)
52
    {
53 2
        $this->pointcutLexer  = $pointcutLexer;
54 2
        $this->pointcutParser = $pointcutParser;
55 2
    }
56
57
    /**
58
     * General method for parsing pointcuts
59
     *
60
     * @param Aspect $aspect Instance of current aspect
61
     * @param Annotation\BaseAnnotation|Annotation\BaseInterceptor $metaInformation
62
     * @param mixed|\ReflectionMethod|\ReflectionProperty $reflection Reflection of point
63
     *
64
     * @throws \UnexpectedValueException if there was an error during parsing
65
     * @return Pointcut|PointFilter
66
     */
67
    protected function parsePointcut(Aspect $aspect, $reflection, $metaInformation)
68
    {
69
        $stream = $this->makeLexicalAnalyze($aspect, $reflection, $metaInformation);
70
71
        return $this->parseTokenStream($reflection, $metaInformation, $stream);
72
    }
73
74
    /**
75
     * Performs lexical analyze of pointcut
76
     *
77
     * @param Aspect $aspect Instance of aspect
78
     * @param ReflectionMethod|ReflectionProperty $reflection
79
     * @param Annotation\BaseAnnotation $metaInformation
80
     *
81
     * @return TokenStream
82
     * @throws \UnexpectedValueException
83
     */
84
    protected function makeLexicalAnalyze(Aspect $aspect, $reflection, $metaInformation)
85
    {
86
        try {
87
            $resolvedThisPointcut = str_replace('$this', get_class($aspect), $metaInformation->value);
88
            $stream = $this->pointcutLexer->lex($resolvedThisPointcut);
89
        } catch (RecognitionException $e) {
90
            $message = "Can not recognize the lexical structure `%s` before %s, defined in %s:%d";
91
            $message = sprintf(
92
                $message,
93
                $metaInformation->value,
94
                (isset($reflection->class) ? $reflection->class . '->' : '') . $reflection->name,
95
                method_exists($reflection, 'getFileName')
96
                    ? $reflection->getFileName()
0 ignored issues
show
Bug introduced by
The method getFileName does only exist in ReflectionMethod, but not in ReflectionProperty.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
97
                    : $reflection->getDeclaringClass()->getFileName(),
98
                method_exists($reflection, 'getStartLine')
99
                    ? $reflection->getStartLine()
0 ignored issues
show
Bug introduced by
The method getStartLine does only exist in ReflectionMethod, but not in ReflectionProperty.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
100
                    : 0
101
            );
102
            throw new \UnexpectedValueException($message, 0, $e);
103
        }
104
105
        return $stream;
106
    }
107
108
    /**
109
     * Performs parsing of pointcut
110
     *
111
     * @param ReflectionMethod|ReflectionProperty $reflection
112
     * @param Annotation\BaseAnnotation $metaInformation
113
     * @param TokenStream $stream
114
     * @return Pointcut
115
     *
116
     * @throws \UnexpectedValueException
117
     */
118
    protected function parseTokenStream($reflection, $metaInformation, $stream)
119
    {
120
        try {
121
            $pointcut = $this->pointcutParser->parse($stream);
122
        } catch (UnexpectedTokenException $e) {
123
            /** @var \Dissect\Lexer\Token $token */
124
            $token   = $e->getToken();
125
            $message = "Unexpected token %s in the `%s` before %s, defined in %s:%d." . PHP_EOL;
126
            $message .= "Expected one of: %s";
127
            $message = sprintf(
128
                $message,
129
                $token->getValue(),
130
                $metaInformation->value,
131
                (isset($reflection->class) ? $reflection->class . '->' : '') . $reflection->name,
132
                method_exists($reflection, 'getFileName')
133
                    ? $reflection->getFileName()
0 ignored issues
show
Bug introduced by
The method getFileName does only exist in ReflectionMethod, but not in ReflectionProperty.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
134
                    : $reflection->getDeclaringClass()->getFileName(),
135
                method_exists($reflection, 'getStartLine')
136
                    ? $reflection->getStartLine()
0 ignored issues
show
Bug introduced by
The method getStartLine does only exist in ReflectionMethod, but not in ReflectionProperty.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
137
                    : 0,
138
                join(', ', $e->getExpected())
139
            );
140
            throw new \UnexpectedValueException($message, 0, $e);
141
        }
142
143
        return $pointcut;
144
    }
145
}
146