PointcutFactory::getInstance()   C
last analyzed

Complexity

Conditions 11
Paths 40

Size

Total Lines 66

Duplication

Lines 14
Ratio 21.21 %

Importance

Changes 0
Metric Value
dl 14
loc 66
rs 6.5951
c 0
b 0
f 0
cc 11
nc 40
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * \AppserverIo\Doppelgaenger\Entities\Pointcuts\PointcutFactory
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Bernhard Wick <[email protected]>
15
 * @copyright 2015 TechDivision GmbH - <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/doppelgaenger
18
 * @link      http://www.appserver.io/
19
 */
20
21
namespace AppserverIo\Doppelgaenger\Entities\Pointcuts;
22
23
use AppserverIo\Doppelgaenger\Utils\Parser;
24
25
/**
26
 * Factory which will produce instances of specific pointcut classes based on their type and expression
27
 *
28
 * @author    Bernhard Wick <[email protected]>
29
 * @copyright 2015 TechDivision GmbH - <[email protected]>
30
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
31
 * @link      https://github.com/appserver-io/doppelgaenger
32
 * @link      http://www.appserver.io/
33
 */
34
class PointcutFactory
35
{
36
37
    /**
38
     * Will look for a logically balanced connector pointcut of a certain type
39
     *
40
     * @param string $expression String to be analysed for potential connector pointcut use
41
     * @param string $class      Type of connector pointcut to look for
42
     *
43
     * @return boolean|\AppserverIo\Doppelgaenger\Interfaces\PointcutInterface
44
     */
45
    protected function findConnectorPointcut($expression, $class)
46
    {
47
        // break up the string at the defined connectors and check for the bracket count on each side.
48
        // an even bracket count on both sides means we found the outermost connection
49
        $connector = constant($class . '::CONNECTOR');
50
        if (strpos($expression, $connector) !== false) {
51
            $connectorCount = substr_count($expression, $connector);
52
            $connectionIndex = 0;
53
54
            // get a parsing helper and analyze bracket counts to determine where we are at
55
            $parserUtil = new Parser();
56
            for ($i = 0; $i < $connectorCount; $i++) {
57
                $connectionIndex = strpos($expression, $connector, $connectionIndex + 1);
58
                $leftCandidate = substr($expression, 0, $connectionIndex);
59
                $rightCandidate = str_replace($leftCandidate . $connector, '', $expression);
60
61
                $leftBrackets = $parserUtil->getBracketCount($leftCandidate, '(');
62
                if ($leftBrackets === 0 && !empty($leftCandidate)) {
63
                    if ($parserUtil->getBracketCount($rightCandidate, '(') === 0 && !empty($rightCandidate)) {
64
                        return new $class($leftCandidate, $rightCandidate);
65
                    }
66
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
67
                }
68
            }
69
        }
70
71
        // if we arrived here we did not find anything
72
        return false;
73
    }
74
75
    /**
76
     * Will return an instance of an AbstractPointcut based on the given expression
77
     *
78
     * @param string $expression Expression specifying a certain pointcut
79
     *
80
     * @return \AppserverIo\Doppelgaenger\Interfaces\PointcutInterface
81
     *
82
     * @throws \InvalidArgumentException
83
     */
84
    public function getInstance($expression)
85
    {
86
        // might be a simple type of pointcut
87
        $isNegated = false;
88
89
        // there are advices which do not reference any pointcuts, spare them the parsing
90
        if (empty($expression)) {
91
            $type = 'blank';
92
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
93
        } else {
94
            // first of all we have to get the type of the pointcut
95
            // check for connector pointcuts first
96
            $expression = trim($expression);
97
98
            // if we are already in a wrapping connector pointcut then we will cut it off as those are not distinguished
99
            // by type but rather by their connector
100
            $expression = $this->trimConnectorTypes($expression);
101
102
            // now lets have a look if we are wrapped in some outer brackets
103
            $parserUtil = new Parser();
104
            if (strlen($expression) === $parserUtil->getBracketSpan($expression, '(')) {
105
                $expression = substr($expression, 1, strlen($expression) - 2);
106
            }
107
108
            // now check if we do have any "and" connectors here
109 View Code Duplication
            if (strpos($expression, AndPointcut::CONNECTOR) !== false) {
110
                $class = '\AppserverIo\Doppelgaenger\Entities\Pointcuts\AndPointcut';
111
                $tmp = $this->findConnectorPointcut($expression, $class);
112
                if ($tmp !== false) {
113
                    return $tmp;
114
                }
115
            }
116
117
            // or-connection comes second
118 View Code Duplication
            if (strpos($expression, OrPointcut::CONNECTOR) !== false) {
119
                $class = '\AppserverIo\Doppelgaenger\Entities\Pointcuts\OrPointcut';
120
                $tmp = $this->findConnectorPointcut($expression, $class);
121
                if ($tmp !== false) {
122
                    return $tmp;
123
                }
124
            }
125
126
            // trim the expression from containing brackets first
127
            while ($expression[0] === '(' && $expression[strlen($expression) - 1] === ')') {
128
                $expression = substr($expression, 1, strlen($expression) - 2);
129
            }
130
131
            if (strpos($expression, '!') !== false) {
132
                $isNegated = true;
133
                $expression = str_replace('!', '', $expression);
134
            }
135
            $type = trim(strstr($expression, '(', true));
136
        }
137
138
        // build up the class name and check if we know a class like that
139
        $class = '\AppserverIo\Doppelgaenger\Entities\Pointcuts\\' . ucfirst($type) . 'Pointcut';
140
141
        // check if we got a valid class
142
        if (!class_exists($class)) {
143
            throw new \InvalidArgumentException(sprintf('Could not resolve the expression %s to any known pointcut type', $expression));
144
        }
145
146
        $pointcut = new $class(substr(trim(str_replace($type, '', $expression), '( '), 0, -1), $isNegated);
147
148
        return $pointcut;
149
    }
150
151
    /**
152
     * Will cut of any connector pointcut type as they are distinguished by connector rather than type
153
     *
154
     * @param string $expression The pointcut expression to trim
155
     *
156
     * @return string
157
     */
158
    protected function trimConnectorTypes($expression)
159
    {
160
        if (strpos($expression, AndPointcut::TYPE) === 0) {
161
            $expression = str_replace(AndPointcut::TYPE, '', $expression);
162
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
163
        } elseif (strpos($expression, OrPointcut::TYPE) === 0) {
164
            $expression = str_replace(OrPointcut::TYPE, '', $expression);
165
        }
166
167
        return $expression;
168
    }
169
}
170