Completed
Push — master ( 121be2...774ac8 )
by Greg
02:16
created

BrowserMob   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 176
Duplicated Lines 10.23 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 13
Bugs 5 Features 3
Metric Value
wmc 41
c 13
b 5
f 3
lcom 1
cbo 6
dl 18
loc 176
rs 8.2769

10 Methods

Rating   Name   Duplication   Size   Complexity  
B _initialize() 0 21 5
A __pingProxy() 0 10 2
D __setProxyCapabilities() 0 45 17
A getProxyPort() 0 4 1
A openProxy() 0 13 3
A closeProxy() 0 8 2
A startHar() 9 9 2
A startPage() 9 9 2
A getHar() 0 4 1
B __call() 0 26 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BrowserMob often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BrowserMob, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Codeception\Extension;
3
4
use Codeception\Module;
5
use Codeception\Exception\ModuleException;
6
use Codeception\Exception\ModuleConfigException;
7
use \PHPBrowserMobProxy_Client as BMP;
8
use \Requests;
9
use \RuntimeException;
10
11
/**
12
 * @method void _open()
13
 * @method void _close()
14
 * @method string _newHar(string $label='')
15
 * @method string _newPage(string $label='')
16
 * @method string _blacklist(string $regexp, integer $status_code)
17
 * @method string _whitelist(string $regexp, integer $status_code)
18
 * @method string _basicAuth(string $domain, string[] $options)
19
 * @method string _headers(string[] $options)
20
 * @method string _responseInterceptor(string $js)
21
 * @method string _requestInterceptor(string $js)
22
 * @method Requests_Response _limits(string[] $options)
23
 * @method Requests_Response _timeouts(string[] $options)
24
 * @method string _remapHosts(string $address, string $ip_address)
25
 * @method string _waitForTrafficToStop(integer $quiet_period, integer $timeout)
26
 * @method string _clearDnsCache()
27
 * @method string _rewriteUrl(string $match, string $replace)
28
 * @method string _retry(integer $retry_count)
29
 */
30
class BrowserMob extends Module
31
{
32
33
    protected $config = ['host', 'port', 'autostart', 'blacklist', 'whitelist', 'limits', 'timeouts', 'redirect', 'retry', 'basicAuth', 'littleproxy'];
34
35
    protected $requiredFields = ['host'];
36
37
    protected $response;
38
39
    private $bmp;
40
41
    /**
42
     * @codeCoverageIgnore
43
     * @ignore Codeception specific
44
     */
45
    public function _initialize()
46
    {
47
        $host = $this->config['host'];
48
        if (isset($this->config['port'])) {
49
            $host = $host.':'.$this->config['port'];
50
        }
51
52
        // test if proxy is available
53
        if (static::__pingProxy($host)) {
54
            $this->bmp = new BMP($host);
55
        } else {
56
            throw new ModuleConfigException(__CLASS__, "Proxy '{$host}' cannot be reached");
57
        }
58
59
        // start a new BrowserMobProxy session
60
        if (isset($this->config['autostart'])) {
61
            if (true === (bool) $this->config['autostart']) {
62
                $this->openProxy();
63
            }
64
        }
65
    }
66
67
    protected static function __pingProxy($url)
68
    {
69
        try {
70
            $response = Requests::get('http://'.$url.'/proxy/');
71
        } catch (\Exception $e) {
72
            throw new ModuleException(__CLASS__, $e->getMessage());
73
        }
74
75
        return $response->success;
76
    }
77
78
    protected function __setProxyCapabilities($capabilities)
79
    {
80
        $response = null;
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
81
82
        foreach ($capabilities as $config => $data) {
83
            if (false === empty($data)) {
84
                switch ((string) $config) {
85
                    case 'blacklist':
86
                        foreach ($data['patterns'] as $pattern) {
87
                            $this->_blacklist($pattern, $data['code']);
88
                            if (false === $this->response->success) break;
89
                        }
90
                        break;
91
                    case 'whitelist':
92
                        $patterns = implode(',', $data['patterns']);
93
                        $this->_whitelist($patterns, $data['code']);
94
                        if (false === $this->response->success) break;
95
                        break;
96
                    case 'limits':
97
                        $this->_limits($data);
98
                        break;
99
                    case 'timeouts':
100
                        $this->_timeouts($data);
101
                        break;
102
                    case 'redirect':
103
                        foreach ($data as $entry) {
104
                            $this->_remapHosts($entry['address'], $entry['ip']);
105
                            if (false === $this->response->success) break;
106
                        }
107
                        break;
108
                    case 'retry':
109
                        $this->_retry($data);
110
                        break;
111
                    case 'basicAuth':
112
                        foreach ($data as $entry) {
113
                            $this->_basicAuth($entry['domain'], $entry['options']);
114
                            if (false === $this->response->success) break;
115
                        }
116
                        break;
117
                    default:
118
                        // do nothing
119
                }
120
            }
121
        }
122
    }
123
124
    public function getProxyPort()
125
    {
126
        return $this->bmp->port;
127
    }
128
129
    public function openProxy($capabilities = null)
130
    {
131
        try {
132
            $this->bmp->open();
133
        } catch (\Exception $e) {
134
            throw new ModuleException(__CLASS__, $e->getMessage());
135
        }
136
        if (empty($capabilities)) {
137
            $capabilities = $this->config;
1 ignored issue
show
Coding Style introduced by
Consider using a different name than the parameter $capabilities. This often makes code more readable.
Loading history...
138
        }
139
        $this->__setProxyCapabilities($capabilities);
140
        return $this->getProxyPort();
141
    }
142
143
    public function closeProxy()
144
    {
145
        try {
146
            $this->bmp->close();
147
        } catch (\Exception $e) {
148
            throw new ModuleException(__CLASS__, $e->getMessage());
149
        }
150
    }
151
152 View Code Duplication
    public function startHar()
153
    {
154
        try {
155
            $this->response = $this->bmp->newHar();
156
        } catch (\Exception $e) {
157
            throw new ModuleException(__CLASS__, $e->getMessage());
158
        }
159
        return $this->response->success;
160
    }
161
162 View Code Duplication
    public function startPage()
163
    {
164
        try {
165
            $this->response = $this->bmp->newPage();
166
        } catch (\Exception $e) {
167
            throw new ModuleException(__CLASS__, $e->getMessage());
168
        }
169
        return $this->response->success;
170
    }
171
172
    public function getHar()
173
    {
174
        return $this->bmp->har;
175
    }
176
177
    // magic function that exposes BrowserMobProxy API pulic methods
178
    public function __call($method, $args)
179
    {
180
        // check if is a command call
181
        if (preg_match('/^_[A-z]+$/', $method)) {
182
            // extract standard method name
183
            $method = preg_filter('/_/', '', $method);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $method. This often makes code more readable.
Loading history...
184
            // set call array for calling method
185
            $call = array($this->bmp, $method);
186
            // check if method is callable
187
            if (is_callable($call)) {
188
                $ret = call_user_func_array($call, $args);
189
                if (get_class($ret) === 'Requests_Response') {
190
                    $this->response = $ret;
191
                    if (false === $ret->success) {
192
                        throw new ModuleConfigException(__CLASS__, "Proxy response error '{$ret->status_code}' {$ret->body}");
193
                    }
194
                }
195
            } else {
196
                throw new RuntimeException("Method ${method} does not exist or is not callable");
197
            }
198
        } else {
199
            throw new RuntimeException("Method ${method} does not exist or is not callable");
200
        }
201
        $ret = (isset($ret)) ? $ret : null;
202
        return $ret;
203
    }
204
205
}
206